Commit 1abc59b7 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

aout: partly rewrite and move filters initialization code

 - simplify "audio-filter" parser and fix a tautology
 - keep a single pointer for the resampler instead of a table
parent 714c9998
......@@ -51,15 +51,6 @@ struct aout_input_t
{
unsigned samplerate; /**< Input sample rate */
/* filters */
filter_t * pp_filters[AOUT_MAX_FILTERS];
unsigned i_nb_filters;
filter_t * p_playback_rate_filter;
/* Resampler + converter to mixer */
filter_t * pp_resamplers[5];
unsigned i_nb_resamplers;
int i_resampling_type;
mtime_t i_resamp_start_date;
int i_resamp_start_drift;
......@@ -69,10 +60,6 @@ struct aout_input_t
/* */
int i_buffer_lost;
/* */
bool b_recycle_vout;
aout_request_vout_t request_vout;
};
typedef struct
......@@ -87,12 +74,20 @@ typedef struct
date_t date;
} sync;
audio_sample_format_t mixer_format;
audio_sample_format_t input_format;
audio_sample_format_t mixer_format;
/* Filters between mixer and output */
filter_t *filters[5];
unsigned nb_filters;
filter_t *rate_filter; /**< The filter adjusting samples count
(either the scaletempo filter or a resampler) */
filter_t *resampler; /**< The resampler */
filter_t *filters[AOUT_MAX_FILTERS]; /**< Configured user filters
(e.g. equalization) and their conversions */
unsigned nb_filters;
unsigned nb_converters;
filter_t *converters[5]; /**< Converters to the output */
aout_request_vout_t request_vout;
bool recycle_vout;
vlc_atomic_t restart;
} aout_owner_t;
......@@ -128,6 +123,10 @@ int aout_FiltersCreatePipeline( vlc_object_t *, filter_t **, unsigned *,
void aout_FiltersDestroyPipeline( filter_t *const *, unsigned );
void aout_FiltersPlay( filter_t *const *, unsigned, block_t ** );
int aout_FiltersNew(audio_output_t *, const audio_sample_format_t *,
const audio_sample_format_t *, const aout_request_vout_t *);
void aout_FiltersDestroy(audio_output_t *);
/* From mixer.c : */
aout_volume_t *aout_volume_New(vlc_object_t *, const audio_replay_gain_t *);
#define aout_volume_New(o, g) aout_volume_New(VLC_OBJECT(o), g)
......
......@@ -138,7 +138,7 @@ static void aout_CheckRestart (audio_output_t *aout)
assert (restart & AOUT_RESTART_INPUT);
const aout_request_vout_t request_vout = owner->input->request_vout;
const aout_request_vout_t request_vout = owner->request_vout;
if (likely(owner->input != NULL))
aout_InputDelete (aout, owner->input);
......
......@@ -28,17 +28,18 @@
# include "config.h"
#endif
#include <string.h>
#include <assert.h>
#include <vlc_common.h>
#include <vlc_dialog.h>
#include <vlc_modules.h>
#include <vlc_aout.h>
#include <vlc_filter.h>
#include <vlc_cpu.h>
#include "aout_internal.h"
#include <vlc_vout.h> /* for vout_Request */
#include <libvlc.h>
#include "aout_internal.h"
/*****************************************************************************
* FindFilter: find an audio filter for a specific transformation
......@@ -211,6 +212,12 @@ void aout_FiltersDestroyPipeline( filter_t *const *filters, unsigned n )
}
}
static inline bool ChangeFiltersString (vlc_object_t *aout, const char *var,
const char *filter, bool add)
{
return aout_ChangeFilterString (aout, aout, var, filter, add);
}
/**
* Filters an audio buffer through a chain of filters.
*/
......@@ -230,3 +237,302 @@ void aout_FiltersPlay( filter_t *const *pp_filters,
}
*pp_block = p_block;
}
/** Callback for visualization selection */
static int VisualizationCallback (vlc_object_t *obj, char const *var,
vlc_value_t oldval, vlc_value_t newval,
void *data)
{
audio_output_t *aout = (audio_output_t *)obj;
const char *mode = newval.psz_string;
if (!*mode)
{
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "visual", false);
ChangeFiltersString (obj, "audio-visual", "projectm", false);
ChangeFiltersString (obj, "audio-visual", "vsxu", false);
}
else if (!strcmp ("goom", mode))
{
ChangeFiltersString (obj, "audio-visual", "visual", false );
ChangeFiltersString (obj, "audio-visual", "goom", true );
ChangeFiltersString (obj, "audio-visual", "projectm", false );
ChangeFiltersString (obj, "audio-visual", "vsxu", false);
}
else if (!strcmp ("projectm", mode))
{
ChangeFiltersString (obj, "audio-visual", "visual", false);
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "projectm", true);
ChangeFiltersString (obj, "audio-visual", "vsxu", false);
}
else if (!strcmp ("vsxu", mode))
{
ChangeFiltersString (obj, "audio-visual", "visual", false);
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "projectm", false);
ChangeFiltersString (obj, "audio-visual", "vsxu", true);
}
else
{
var_Create (obj, "effect-list", VLC_VAR_STRING);
var_SetString (obj, "effect-list", mode);
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "visual", true);
ChangeFiltersString (obj, "audio-visual", "projectm", false);
}
aout_InputRequestRestart (aout);
(void) var; (void) oldval; (void) data;
return VLC_SUCCESS;
}
static int EqualizerCallback (vlc_object_t *obj, char const *var,
vlc_value_t oldval, vlc_value_t newval,
void *data)
{
audio_output_t *aout = (audio_output_t *)obj;
char *mode = newval.psz_string;
bool ret;
if (!*mode)
ret = ChangeFiltersString (obj, "audio-filter", "equalizer", false);
else
{
var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
var_SetString (obj, "equalizer-preset", mode);
ret = ChangeFiltersString (obj, "audio-filter", "equalizer", true);
}
/* That sucks */
if (ret)
aout_InputRequestRestart (aout);
(void) var; (void) oldval; (void) data;
return VLC_SUCCESS;
}
static vout_thread_t *RequestVout (void *data, vout_thread_t *vout,
video_format_t *fmt, bool recycle)
{
audio_output_t *aout = data;
vout_configuration_t cfg = {
.vout = vout,
.input = NULL,
.change_fmt = true,
.fmt = fmt,
.dpb_size = 1,
};
(void) recycle;
return vout_Request (aout, &cfg);
}
vout_thread_t *aout_filter_RequestVout (filter_t *filter, vout_thread_t *vout,
video_format_t *fmt)
{
/* NOTE: This only works from audio output.
* If you want to use visualization filters from another place, you will
* need to add a new pf_aout_request_vout callback or store a pointer
* to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
aout_owner_t *owner = aout_owner ((audio_output_t *)filter->p_parent);
aout_request_vout_t *req = &owner->request_vout;
return req->pf_request_vout (req->p_private, vout, fmt,
owner->recycle_vout);
}
static filter_t *CreateFilter (vlc_object_t *parent, const char *name,
const audio_sample_format_t *restrict infmt,
const audio_sample_format_t *restrict outfmt,
bool visu)
{
filter_t *filter = vlc_custom_create (parent, sizeof (*filter),
"audio filter");
if (unlikely(filter == NULL))
return NULL;
/*filter->p_owner = NOT NEEDED;*/
filter->fmt_in.i_codec = infmt->i_format;
filter->fmt_in.audio = *infmt;
filter->fmt_out.i_codec = outfmt->i_format;
filter->fmt_out.audio = *outfmt;
if (!visu)
{
filter->p_module = module_need (filter, "audio filter", name, true);
if (filter->p_module != NULL)
return filter;
/* If probing failed, formats shall not have been modified. */
assert (AOUT_FMTS_IDENTICAL(&filter->fmt_in.audio, infmt));
assert (AOUT_FMTS_IDENTICAL(&filter->fmt_out.audio, outfmt));
}
filter->p_module = module_need (filter, "visualization2", name, true);
if (filter->p_module != NULL)
return filter;
vlc_object_release (filter);
return NULL;
}
/**
* Sets up the audio filters.
*/
int aout_FiltersNew (audio_output_t *aout,
const audio_sample_format_t *restrict infmt,
const audio_sample_format_t *restrict outfmt,
const aout_request_vout_t *request_vout)
{
aout_owner_t *owner = aout_owner (aout);
/* Prepare format structure */
aout_FormatPrint (aout, "input", infmt);
audio_sample_format_t input_format = *infmt;
audio_sample_format_t output_format = *outfmt;
/* Now add user filters */
owner->nb_filters = 0;
owner->rate_filter = NULL;
owner->resampler = NULL;
if (!AOUT_FMT_LINEAR(outfmt))
return 0;
var_AddCallback (aout, "visual", VisualizationCallback, NULL);
var_AddCallback (aout, "equalizer", EqualizerCallback, NULL);
bool scaletempo = var_InheritBool (aout, "audio-time-stretch");
char *filters = var_InheritString (aout, "audio-filter");
char *visual = var_InheritString (aout, "audio-visual");
if (request_vout != NULL)
owner->request_vout = *request_vout;
else
{
owner->request_vout.pf_request_vout = RequestVout;
owner->request_vout.p_private = aout;
}
owner->recycle_vout = (visual != NULL) && *visual;
/* parse user filter lists */
const char *list[AOUT_MAX_FILTERS];
unsigned n = 0;
if (scaletempo)
list[n++] = "scaletempo";
if (filters != NULL)
{
char *p = filters, *name;
while ((name = strsep (&p, " :")) != NULL && n < AOUT_MAX_FILTERS)
list[n++] = name;
}
if (visual != NULL && n < AOUT_MAX_FILTERS)
list[n++] = visual;
for (unsigned i = 0; i < n; i++)
{
const char *name = list[i];
if (owner->nb_filters >= AOUT_MAX_FILTERS)
{
msg_Err (aout, "maximum of %u filters reached", AOUT_MAX_FILTERS);
msg_Err (aout, "cannot add user filter %s (skipped)", name);
break;
}
filter_t *filter = CreateFilter (VLC_OBJECT(aout), name,
&input_format, &output_format,
i == (n - (visual != NULL)));
if (filter == NULL)
{
msg_Err (aout, "cannot add user filter %s (skipped)", name);
continue;
}
/* convert to the filter input format if necessary */
if (aout_FiltersCreatePipeline (VLC_OBJECT(aout), owner->filters,
&owner->nb_filters,
AOUT_MAX_FILTERS - 1,
&input_format, &filter->fmt_in.audio))
{
msg_Err (aout, "cannot add user filter %s (skipped)", name);
module_unneed (filter, filter->p_module);
vlc_object_release (filter);
continue;
}
assert (owner->nb_filters < AOUT_MAX_FILTERS);
owner->filters[owner->nb_filters++] = filter;
input_format = filter->fmt_out.audio;
if (i == 0 && scaletempo) /* scaletempo */
owner->rate_filter = filter;
}
free (visual);
free (filters);
/* convert to the output format (minus resampling) if necessary */
output_format.i_rate = input_format.i_rate;
if (aout_FiltersCreatePipeline (VLC_OBJECT(aout), owner->filters,
&owner->nb_filters, AOUT_MAX_FILTERS,
&input_format, &output_format))
{
msg_Err (aout, "cannot setup filtering pipeline");
goto error;
}
input_format = output_format;
/* insert the resampler */
output_format.i_rate = outfmt->i_rate;
assert (AOUT_FMTS_IDENTICAL(&output_format, outfmt));
unsigned rate_bak = input_format.i_rate;
if (output_format.i_rate == input_format.i_rate)
/* For historical reasons, a different rate is required to probe
* resampling filters. */
input_format.i_rate++;
owner->resampler = FindFilter (VLC_OBJECT(aout), &input_format,
&output_format);
if (owner->resampler == NULL)
{
msg_Err (aout, "cannot setup a resampler");
goto error;
}
owner->resampler->fmt_in.audio.i_rate = rate_bak;
if (owner->rate_filter == NULL)
owner->rate_filter = owner->resampler;
return 0;
error:
aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
var_DelCallback (aout, "equalizer", EqualizerCallback, NULL);
var_DelCallback (aout, "visual", VisualizationCallback, NULL);
return -1;
}
/**
* Destroys the audio filters.
*/
void aout_FiltersDestroy (audio_output_t *aout)
{
aout_owner_t *owner = aout_owner (aout);
if (owner->resampler != NULL)
aout_FiltersDestroyPipeline (&owner->resampler, 1);
aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
var_DelCallback (aout, "equalizer", EqualizerCallback, NULL);
var_DelCallback (aout, "visual", VisualizationCallback, NULL);
/* XXX We need to update recycle_vout before calling
* aout_FiltersDestroyPipeline().
* FIXME There may be a race condition if audio-visual is updated between
* aout_FiltersDestroy() and the next aout_FiltersNew().
*/
char *visual = var_InheritString (aout, "audio-visual");
owner->recycle_vout = (visual != NULL) && *visual;
free (visual);
}
......@@ -30,30 +30,15 @@
#endif
#include <vlc_common.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <vlc_input.h>
#include <vlc_vout.h> /* for vout_Request */
#include <vlc_modules.h>
#include <vlc_aout.h>
#include <vlc_filter.h>
#include <libvlc.h>
#include <libvlc.h>
#include "aout_internal.h"
static void inputDrop( aout_input_t *, block_t * );
static void inputResamplingStop( aout_input_t *p_input );
static int VisualizationCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static int EqualizerCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static vout_thread_t *RequestVout( void *,
vout_thread_t *, video_format_t *, bool );
static void inputResamplingStop( audio_output_t *, aout_input_t * );
/*****************************************************************************
* aout_InputNew : allocate a new input and rework the filter pipeline
......@@ -67,232 +52,18 @@ aout_input_t *aout_InputNew (audio_output_t * p_aout,
if (unlikely(p_input == NULL))
return NULL;
aout_FormatPrint( p_aout, "input", infmt );
p_input->samplerate = infmt->i_rate;
p_input->i_nb_resamplers = p_input->i_nb_filters = 0;
/* */
if( p_request_vout )
{
p_input->request_vout = *p_request_vout;
}
else
{
p_input->request_vout.pf_request_vout = RequestVout;
p_input->request_vout.p_private = p_aout;
}
/* Prepare format structure */
audio_sample_format_t chain_input_format = *infmt;
audio_sample_format_t chain_output_format = *outfmt;
chain_output_format.i_rate = infmt->i_rate;
aout_FormatPrepare( &chain_output_format );
/* Now add user filters */
var_AddCallback( p_aout, "visual", VisualizationCallback, p_input );
var_AddCallback( p_aout, "equalizer", EqualizerCallback, p_input );
char *psz_filters = var_GetString( p_aout, "audio-filter" );
char *psz_visual = var_GetString( p_aout, "audio-visual");
char *psz_scaletempo = var_InheritBool( p_aout, "audio-time-stretch" ) ? strdup( "scaletempo" ) : NULL;
p_input->b_recycle_vout = psz_visual && *psz_visual;
/* parse user filter lists */
char *const ppsz_array[] = { psz_scaletempo, psz_filters, psz_visual };
p_input->p_playback_rate_filter = NULL;
for (unsigned i_visual = 0;
i_visual < 3 && AOUT_FMT_LINEAR(&chain_output_format);
i_visual++)
if (aout_FiltersNew (p_aout, infmt, outfmt, p_request_vout))
{
char *psz_next = NULL;
char *psz_parser = ppsz_array[i_visual];
if( psz_parser == NULL || !*psz_parser )
continue;
while( psz_parser && *psz_parser )
{
filter_t * p_filter = NULL;
if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
{
msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS );
break;
}
while( *psz_parser == ' ' && *psz_parser == ':' )
{
psz_parser++;
}
if( ( psz_next = strchr( psz_parser , ':' ) ) )
{
*psz_next++ = '\0';
}
if( *psz_parser =='\0' )
{
break;
}
/* Create a VLC object */
p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
"audio filter" );
if( p_filter == NULL )
{
msg_Err( p_aout, "cannot add user filter %s (skipped)",
psz_parser );
psz_parser = psz_next;
continue;
}
p_filter->p_owner = (filter_owner_sys_t *)p_input;
/* request format */
memcpy( &p_filter->fmt_in.audio, &chain_output_format,
sizeof(audio_sample_format_t) );
p_filter->fmt_in.i_codec = chain_output_format.i_format;
memcpy( &p_filter->fmt_out.audio, &chain_output_format,
sizeof(audio_sample_format_t) );
p_filter->fmt_out.i_codec = chain_output_format.i_format;
/* try to find the requested filter */
if( i_visual == 2 ) /* this can only be a visualization module */
{
p_filter->p_module = module_need( p_filter, "visualization2",
psz_parser, true );
}
else /* this can be a audio filter module as well as a visualization module */
{
p_filter->p_module = module_need( p_filter, "audio filter",
psz_parser, true );
if ( p_filter->p_module == NULL )
{
/* if the filter requested a special format, retry */
if ( !( AOUT_FMTS_IDENTICAL( &p_filter->fmt_in.audio,
&chain_input_format )
&& AOUT_FMTS_IDENTICAL( &p_filter->fmt_out.audio,
&chain_output_format ) ) )
{
aout_FormatPrepare( &p_filter->fmt_in.audio );
aout_FormatPrepare( &p_filter->fmt_out.audio );
p_filter->p_module = module_need( p_filter,
"audio filter",
psz_parser, true );
}
/* try visual filters */
else
{
memcpy( &p_filter->fmt_in.audio, &chain_output_format,
sizeof(audio_sample_format_t) );
memcpy( &p_filter->fmt_out.audio, &chain_output_format,
sizeof(audio_sample_format_t) );
p_filter->p_module = module_need( p_filter,
"visualization2",
psz_parser, true );
}
}
}
/* failure */
if ( p_filter->p_module == NULL )
{
msg_Err( p_aout, "cannot add user filter %s (skipped)",
psz_parser );
vlc_object_release( p_filter );
psz_parser = psz_next;
continue;
}
/* complete the filter chain if necessary */
if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
&p_input->i_nb_filters,
AOUT_MAX_FILTERS,
&chain_input_format,
&p_filter->fmt_in.audio ) < 0 )
{
msg_Err( p_aout, "cannot add user filter %s (skipped)",
psz_parser );
module_unneed( p_filter, p_filter->p_module );
vlc_object_release( p_filter );
psz_parser = psz_next;
continue;
}
/* success */
p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
memcpy( &chain_input_format, &p_filter->fmt_out.audio,
sizeof( audio_sample_format_t ) );
if( i_visual == 0 ) /* scaletempo */
p_input->p_playback_rate_filter = p_filter;
/* next filter if any */
psz_parser = psz_next;
}
}
free( psz_visual );
free( psz_filters );
free( psz_scaletempo );
/* complete the filter chain if necessary */
if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
&p_input->i_nb_filters, AOUT_MAX_FILTERS,
&chain_input_format,
&chain_output_format ) < 0 )
{
msg_Err (p_aout, "cannot setup filtering pipeline");
goto error;
free(p_input);
return NULL;
}
/* Create resamplers. */
if (AOUT_FMT_LINEAR(outfmt))
{
chain_output_format.i_rate = (__MAX(p_input->samplerate,
outfmt->i_rate)
* (100 + AOUT_MAX_RESAMPLING)) / 100;
if ( chain_output_format.i_rate == outfmt->i_rate )
{
/* Just in case... */
chain_output_format.i_rate++;
}
if (aout_FiltersCreatePipeline (p_aout, p_input->pp_resamplers,
&p_input->i_nb_resamplers,
sizeof (p_input->pp_resamplers)
/ sizeof (p_input->pp_resamplers[0]),
&chain_output_format, outfmt) < 0)
{
msg_Err (p_aout, "cannot setup a resampling pipeline");
goto error;
}
/* Setup the initial rate of the resampler */
p_input->pp_resamplers[0]->fmt_in.audio.i_rate = p_input->samplerate;
}
p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
if( ! p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0 )
{
p_input->p_playback_rate_filter = p_input->pp_resamplers[0];
}
/* Success */
p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
p_input->i_buffer_lost = 0;
return p_input;
error:
aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
aout_FiltersDestroyPipeline( p_input->pp_resamplers,
p_input->i_nb_resamplers );
free (p_input);
return NULL;
}
/*****************************************************************************
......@@ -302,23 +73,8 @@ error:
*****************************************************************************/
int aout_InputDelete( audio_output_t * p_aout, aout_input_t * p_input )
{
var_DelCallback (p_aout, "equalizer", EqualizerCallback, p_input);
var_DelCallback (p_aout, "visual", VisualizationCallback, p_input);
/* XXX We need to update b_recycle_vout before calling aout_FiltersDestroyPipeline.
* FIXME They can be a race condition if audio-visual is updated between
* aout_InputDelete and aout_InputNew.
*/
char *psz_visual = var_GetString( p_aout, "audio-visual");
p_input->b_recycle_vout = psz_visual && *psz_visual;
free( psz_visual );
aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
p_input->i_nb_filters = 0;
aout_FiltersDestroyPipeline( p_input->pp_resamplers,
p_input->i_nb_resamplers );
p_input->i_nb_resamplers = 0;
aout_FiltersDestroy (p_aout);
(void) p_input;
return 0;
}
......@@ -331,10 +87,11 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
block_t *p_buffer, int i_input_rate, date_t *date )
{
mtime_t start_date;
aout_owner_t *owner = aout_owner(p_aout);
aout_assert_locked( p_aout );
if( i_input_rate != INPUT_RATE_DEFAULT && p_input->p_playback_rate_filter == NULL )
if( i_input_rate != INPUT_RATE_DEFAULT && owner->rate_filter == NULL )
{
inputDrop( p_input, p_buffer );
return NULL;
......@@ -343,7 +100,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
/* Handle input rate change, but keep drift correction */
if( i_input_rate != p_input->i_last_input_rate )
{
unsigned int * const pi_rate = &p_input->p_playback_rate_filter->fmt_in.audio.i_rate;
unsigned int * const pi_rate = &owner->rate_filter->fmt_in.audio.i_rate;
#define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
const int i_delta = *pi_rate - F(p_input->samplerate,p_input->i_last_input_rate);
*pi_rate = F(p_input->samplerate + i_delta, i_input_rate);
......@@ -368,7 +125,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
aout_OutputFlush( p_aout, false );
if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
msg_Warn( p_aout, "timing screwed, stopping resampling" );
inputResamplingStop( p_input );
inputResamplingStop( p_aout, p_input );
p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
start_date = VLC_TS_INVALID;
}
......@@ -380,7 +137,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
now - p_buffer->i_pts );
inputDrop( p_input, p_buffer );
inputResamplingStop( p_input );
inputResamplingStop( p_aout, p_input );
return NULL;
}
......@@ -401,7 +158,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
aout_OutputFlush( p_aout, false );
if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
msg_Warn( p_aout, "timing screwed, stopping resampling" );
inputResamplingStop( p_input );
inputResamplingStop( p_aout, p_input );
p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
start_date = p_buffer->i_pts;
date_Set (date, start_date);
......@@ -417,7 +174,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
}
/* Run pre-filters. */
aout_FiltersPlay( p_input->pp_filters, p_input->i_nb_filters, &p_buffer );
aout_FiltersPlay( owner->filters, owner->nb_filters, &p_buffer );
if( !p_buffer )
return NULL;
......@@ -425,7 +182,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
* We first need to calculate the output rate of this resampler. */
if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
( drift < -AOUT_MAX_PTS_ADVANCE || drift > +AOUT_MAX_PTS_DELAY ) &&
p_input->i_nb_resamplers > 0 )
owner->resampler != NULL )
{
/* Can happen in several circumstances :
* 1. A problem at the input (clock drift)
......@@ -450,17 +207,17 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
* it isn't too audible to the listener. */
if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
p_input->pp_resamplers[0]->fmt_in.audio.i_rate += 2; /* Hz */
owner->resampler->fmt_in.audio.i_rate += 2; /* Hz */
else
p_input->pp_resamplers[0]->fmt_in.audio.i_rate -= 2; /* Hz */
owner->resampler->fmt_in.audio.i_rate -= 2; /* Hz */
/* Check if everything is back to normal, in which case we can stop the
* resampling */
unsigned int i_nominal_rate =
(p_input->pp_resamplers[0] == p_input->p_playback_rate_filter)
(owner->resampler == owner->rate_filter)
? INPUT_RATE_DEFAULT * p_input->samplerate / i_input_rate
: p_input->samplerate;
if( p_input->pp_resamplers[0]->fmt_in.audio.i_rate == i_nominal_rate )
if( owner->resampler->fmt_in.audio.i_rate == i_nominal_rate )
{
p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
msg_Warn( p_aout, "resampling stopped after %"PRIi64" usec "
......@@ -486,17 +243,14 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
/* If the drift is increasing and not decreasing, than something
* is bad. We'd better stop the resampling right now. */
msg_Warn( p_aout, "timing screwed, stopping resampling" );
inputResamplingStop( p_input );
inputResamplingStop( p_aout, p_input );
p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
}
}
/* Actually run the resampler now. */
if ( p_input->i_nb_resamplers > 0 )
{
aout_FiltersPlay( p_input->pp_resamplers, p_input->i_nb_resamplers,
&p_buffer );
}
if ( owner->resampler != NULL )
aout_FiltersPlay( &owner->resampler, 1, &p_buffer );
if( !p_buffer )
return NULL;
......@@ -521,128 +275,16 @@ static void inputDrop( aout_input_t *p_input, block_t *p_buffer )
p_input->i_buffer_lost++;
}
static void inputResamplingStop( aout_input_t *p_input )
static void inputResamplingStop( audio_output_t *p_aout, aout_input_t *p_input )
{
aout_owner_t *owner = aout_owner(p_aout);
p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
if( p_input->i_nb_resamplers != 0 )
if( owner->resampler != NULL )
{
p_input->pp_resamplers[0]->fmt_in.audio.i_rate =
( p_input->pp_resamplers[0] == p_input->p_playback_rate_filter )
owner->resampler->fmt_in.audio.i_rate =
( owner->resampler == owner->rate_filter )
? INPUT_RATE_DEFAULT * p_input->samplerate / p_input->i_last_input_rate
: p_input->samplerate;
}
}
static vout_thread_t *RequestVout( void *p_private,
vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
{
audio_output_t *p_aout = p_private;
VLC_UNUSED(b_recycle);
vout_configuration_t cfg = {
.vout = p_vout,
.input = NULL,
.change_fmt = true,
.fmt = p_fmt,
.dpb_size = 1,
};
return vout_Request( p_aout, &cfg );
}
vout_thread_t *aout_filter_RequestVout( filter_t *p_filter,
vout_thread_t *p_vout, video_format_t *p_fmt )
{
aout_input_t *p_input = (aout_input_t *)p_filter->p_owner;
aout_request_vout_t *p_request = &p_input->request_vout;
/* XXX: this only works from audio input */
/* If you want to use visualization filters from another place, you will
* need to add a new pf_aout_request_vout callback or store a pointer
* to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
return p_request->pf_request_vout( p_request->p_private,
p_vout, p_fmt, p_input->b_recycle_vout );
}
static inline bool ChangeFiltersString (vlc_object_t *aout, const char *var,
const char *filter, bool add)
{
return aout_ChangeFilterString (aout, aout, var, filter, add);
}
static int VisualizationCallback (vlc_object_t *obj, char const *var,
vlc_value_t oldval, vlc_value_t newval,
void *data)
{
const char *mode = newval.psz_string;
//aout_input_t *input = data;
(void) data;
if (!*mode)
{
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "visual", false);
ChangeFiltersString (obj, "audio-visual", "projectm", false);
ChangeFiltersString (obj, "audio-visual", "vsxu", false);
}
else if (!strcmp ("goom", mode))
{
ChangeFiltersString (obj, "audio-visual", "visual", false );
ChangeFiltersString (obj, "audio-visual", "goom", true );
ChangeFiltersString (obj, "audio-visual", "projectm", false );
ChangeFiltersString (obj, "audio-visual", "vsxu", false);
}
else if (!strcmp ("projectm", mode))
{
ChangeFiltersString (obj, "audio-visual", "visual", false);
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "projectm", true);
ChangeFiltersString (obj, "audio-visual", "vsxu", false);
}
else if (!strcmp ("vsxu", mode))
{
ChangeFiltersString (obj, "audio-visual", "visual", false);
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "projectm", false);
ChangeFiltersString (obj, "audio-visual", "vsxu", true);
}
else
{
var_Create (obj, "effect-list", VLC_VAR_STRING);
var_SetString (obj, "effect-list", mode);
ChangeFiltersString (obj, "audio-visual", "goom", false);
ChangeFiltersString (obj, "audio-visual", "visual", true);
ChangeFiltersString (obj, "audio-visual", "projectm", false);
}
/* That sucks FIXME: use "input" instead of cast */
aout_InputRequestRestart ((audio_output_t *)obj);
(void) var; (void) oldval;
return VLC_SUCCESS;
}
static int EqualizerCallback (vlc_object_t *obj, char const *cmd,
vlc_value_t oldval, vlc_value_t newval,
void *data)
{
char *mode = newval.psz_string;
//aout_input_t *input = data;
bool ret;
(void) data;
(void) cmd; (void) oldval;
if (!*mode)
ret = ChangeFiltersString (obj, "audio-filter", "equalizer", false);
else
{
var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
var_SetString (obj, "equalizer-preset", mode);
ret = ChangeFiltersString (obj, "audio-filter", "equalizer", true);
}
/* That sucks */
if (ret)
aout_InputRequestRestart ((audio_output_t *)obj);
return VLC_SUCCESS;
}
......@@ -403,11 +403,11 @@ int aout_OutputNew (audio_output_t *aout, const audio_sample_format_t *fmtp)
aout_FormatPrepare (&owner->mixer_format);
aout_FormatPrint (aout, "mixer", &owner->mixer_format);
/* Create filters. */
owner->nb_filters = 0;
if (aout_FiltersCreatePipeline (aout, owner->filters, &owner->nb_filters,
sizeof (owner->filters)
/ sizeof (owner->filters[0]),
/* Create converters. */
owner->nb_converters = 0;
if (aout_FiltersCreatePipeline (aout, owner->converters,
&owner->nb_converters,
sizeof (owner->converters) / sizeof (owner->converters[0]),
&owner->mixer_format, &fmt) < 0)
{
msg_Err (aout, "couldn't create audio output pipeline");
......@@ -431,7 +431,7 @@ void aout_OutputDelete (audio_output_t *aout)
var_DelCallback (aout, "stereo-mode", aout_ChannelsRestart, NULL);
if (aout->stop != NULL)
aout->stop (aout);
aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
aout_FiltersDestroyPipeline (owner->converters, owner->nb_converters);
}
/**
......@@ -446,7 +446,7 @@ void aout_OutputPlay (audio_output_t *aout, block_t *block)
aout_assert_locked (aout);
aout_FiltersPlay (owner->filters, owner->nb_filters, &block);
aout_FiltersPlay (owner->converters, owner->nb_converters, &block);
if (block == NULL)
return;
if (block->i_buffer == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment