1 /*****************************************************************************
2 * input.c : internal management of input streams for the audio output
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
38 #include <vlc_input.h>
39 #include <vlc_vout.h> /* for vout_Request */
40 #include <vlc_modules.h>
42 #include <vlc_filter.h>
45 #include "aout_internal.h"
47 static void inputDrop( aout_input_t *, block_t * );
48 static void inputResamplingStop( aout_input_t *p_input );
50 static int VisualizationCallback( vlc_object_t *, char const *,
51 vlc_value_t, vlc_value_t, void * );
52 static int EqualizerCallback( vlc_object_t *, char const *,
53 vlc_value_t, vlc_value_t, void * );
55 static vout_thread_t *RequestVout( void *,
56 vout_thread_t *, video_format_t *, bool );
58 /*****************************************************************************
59 * aout_InputNew : allocate a new input and rework the filter pipeline
60 *****************************************************************************/
61 aout_input_t *aout_InputNew (audio_output_t * p_aout,
62 const audio_sample_format_t *restrict infmt,
63 const audio_sample_format_t *restrict outfmt,
64 const aout_request_vout_t *p_request_vout)
66 aout_input_t *p_input = malloc (sizeof (*p_input));
67 if (unlikely(p_input == NULL))
70 aout_FormatPrint( p_aout, "input", infmt );
71 p_input->samplerate = infmt->i_rate;
73 p_input->i_nb_resamplers = p_input->i_nb_filters = 0;
78 p_input->request_vout = *p_request_vout;
82 p_input->request_vout.pf_request_vout = RequestVout;
83 p_input->request_vout.p_private = p_aout;
86 /* Prepare format structure */
87 audio_sample_format_t chain_input_format = *infmt;
88 audio_sample_format_t chain_output_format = *outfmt;
90 chain_output_format.i_rate = infmt->i_rate;
91 aout_FormatPrepare( &chain_output_format );
93 /* Now add user filters */
94 var_AddCallback( p_aout, "visual", VisualizationCallback, p_input );
95 var_AddCallback( p_aout, "equalizer", EqualizerCallback, p_input );
97 char *psz_filters = var_GetString( p_aout, "audio-filter" );
98 char *psz_visual = var_GetString( p_aout, "audio-visual");
99 char *psz_scaletempo = var_InheritBool( p_aout, "audio-time-stretch" ) ? strdup( "scaletempo" ) : NULL;
101 p_input->b_recycle_vout = psz_visual && *psz_visual;
103 /* parse user filter lists */
104 char *const ppsz_array[] = { psz_scaletempo, psz_filters, psz_visual };
105 p_input->p_playback_rate_filter = NULL;
107 for (unsigned i_visual = 0;
108 i_visual < 3 && AOUT_FMT_LINEAR(&chain_output_format);
111 char *psz_next = NULL;
112 char *psz_parser = ppsz_array[i_visual];
114 if( psz_parser == NULL || !*psz_parser )
117 while( psz_parser && *psz_parser )
119 filter_t * p_filter = NULL;
121 if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
123 msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS );
127 while( *psz_parser == ' ' && *psz_parser == ':' )
131 if( ( psz_next = strchr( psz_parser , ':' ) ) )
135 if( *psz_parser =='\0' )
140 /* Create a VLC object */
141 p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
143 if( p_filter == NULL )
145 msg_Err( p_aout, "cannot add user filter %s (skipped)",
147 psz_parser = psz_next;
150 p_filter->p_owner = (filter_owner_sys_t *)p_input;
153 memcpy( &p_filter->fmt_in.audio, &chain_output_format,
154 sizeof(audio_sample_format_t) );
155 p_filter->fmt_in.i_codec = chain_output_format.i_format;
156 memcpy( &p_filter->fmt_out.audio, &chain_output_format,
157 sizeof(audio_sample_format_t) );
158 p_filter->fmt_out.i_codec = chain_output_format.i_format;
160 /* try to find the requested filter */
161 if( i_visual == 2 ) /* this can only be a visualization module */
163 p_filter->p_module = module_need( p_filter, "visualization2",
166 else /* this can be a audio filter module as well as a visualization module */
168 p_filter->p_module = module_need( p_filter, "audio filter",
171 if ( p_filter->p_module == NULL )
173 /* if the filter requested a special format, retry */
174 if ( !( AOUT_FMTS_IDENTICAL( &p_filter->fmt_in.audio,
175 &chain_input_format )
176 && AOUT_FMTS_IDENTICAL( &p_filter->fmt_out.audio,
177 &chain_output_format ) ) )
179 aout_FormatPrepare( &p_filter->fmt_in.audio );
180 aout_FormatPrepare( &p_filter->fmt_out.audio );
181 p_filter->p_module = module_need( p_filter,
185 /* try visual filters */
188 memcpy( &p_filter->fmt_in.audio, &chain_output_format,
189 sizeof(audio_sample_format_t) );
190 memcpy( &p_filter->fmt_out.audio, &chain_output_format,
191 sizeof(audio_sample_format_t) );
192 p_filter->p_module = module_need( p_filter,
200 if ( p_filter->p_module == NULL )
202 msg_Err( p_aout, "cannot add user filter %s (skipped)",
205 vlc_object_release( p_filter );
207 psz_parser = psz_next;
211 /* complete the filter chain if necessary */
212 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
213 &p_input->i_nb_filters,
215 &p_filter->fmt_in.audio ) < 0 )
217 msg_Err( p_aout, "cannot add user filter %s (skipped)",
220 module_unneed( p_filter, p_filter->p_module );
221 vlc_object_release( p_filter );
223 psz_parser = psz_next;
228 p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
229 memcpy( &chain_input_format, &p_filter->fmt_out.audio,
230 sizeof( audio_sample_format_t ) );
232 if( i_visual == 0 ) /* scaletempo */
233 p_input->p_playback_rate_filter = p_filter;
235 /* next filter if any */
236 psz_parser = psz_next;
241 free( psz_scaletempo );
243 /* complete the filter chain if necessary */
244 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
245 &p_input->i_nb_filters,
247 &chain_output_format ) < 0 )
249 msg_Err (p_aout, "cannot setup filtering pipeline");
253 /* Create resamplers. */
254 if (AOUT_FMT_LINEAR(outfmt))
256 chain_output_format.i_rate = (__MAX(p_input->samplerate,
258 * (100 + AOUT_MAX_RESAMPLING)) / 100;
259 if ( chain_output_format.i_rate == outfmt->i_rate )
261 /* Just in case... */
262 chain_output_format.i_rate++;
264 if (aout_FiltersCreatePipeline (p_aout, p_input->pp_resamplers,
265 &p_input->i_nb_resamplers,
266 &chain_output_format, outfmt) < 0)
268 msg_Err (p_aout, "cannot setup a resampling pipeline");
272 /* Setup the initial rate of the resampler */
273 p_input->pp_resamplers[0]->fmt_in.audio.i_rate = p_input->samplerate;
275 p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
277 if( ! p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0 )
279 p_input->p_playback_rate_filter = p_input->pp_resamplers[0];
283 p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
284 p_input->i_buffer_lost = 0;
288 aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
289 aout_FiltersDestroyPipeline( p_input->pp_resamplers,
290 p_input->i_nb_resamplers );
295 /*****************************************************************************
296 * aout_InputDelete : delete an input
297 *****************************************************************************
298 * This function must be entered with the mixer lock.
299 *****************************************************************************/
300 int aout_InputDelete( audio_output_t * p_aout, aout_input_t * p_input )
302 var_DelCallback (p_aout, "equalizer", EqualizerCallback, p_input);
303 var_DelCallback (p_aout, "visual", VisualizationCallback, p_input);
305 /* XXX We need to update b_recycle_vout before calling aout_FiltersDestroyPipeline.
306 * FIXME They can be a race condition if audio-visual is updated between
307 * aout_InputDelete and aout_InputNew.
309 char *psz_visual = var_GetString( p_aout, "audio-visual");
310 p_input->b_recycle_vout = psz_visual && *psz_visual;
313 aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
314 p_input->i_nb_filters = 0;
315 aout_FiltersDestroyPipeline( p_input->pp_resamplers,
316 p_input->i_nb_resamplers );
317 p_input->i_nb_resamplers = 0;
322 /*****************************************************************************
323 * aout_InputPlay : play a buffer
324 *****************************************************************************
325 * This function must be entered with the input lock.
326 *****************************************************************************/
327 block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
328 block_t *p_buffer, int i_input_rate, date_t *date )
332 aout_assert_locked( p_aout );
334 if( i_input_rate != INPUT_RATE_DEFAULT && p_input->p_playback_rate_filter == NULL )
336 inputDrop( p_input, p_buffer );
340 /* Handle input rate change, but keep drift correction */
341 if( i_input_rate != p_input->i_last_input_rate )
343 unsigned int * const pi_rate = &p_input->p_playback_rate_filter->fmt_in.audio.i_rate;
344 #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
345 const int i_delta = *pi_rate - F(p_input->samplerate,p_input->i_last_input_rate);
346 *pi_rate = F(p_input->samplerate + i_delta, i_input_rate);
348 p_input->i_last_input_rate = i_input_rate;
351 mtime_t now = mdate();
353 /* We don't care if someone changes the start date behind our back after
354 * this. We'll deal with that when pushing the buffer, and compensate
355 * with the next incoming buffer. */
356 start_date = date_Get (date);
358 if ( start_date != VLC_TS_INVALID && start_date < now )
360 /* The decoder is _very_ late. This can only happen if the user
361 * pauses the stream (or if the decoder is buggy, which cannot
363 msg_Warn( p_aout, "computed PTS is out of range (%"PRId64"), "
364 "clearing out", now - start_date );
365 aout_OutputFlush( p_aout, false );
366 if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
367 msg_Warn( p_aout, "timing screwed, stopping resampling" );
368 inputResamplingStop( p_input );
369 p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
370 start_date = VLC_TS_INVALID;
373 if ( p_buffer->i_pts < now + AOUT_MIN_PREPARE_TIME )
375 /* The decoder gives us f*cked up PTS. It's its business, but we
376 * can't present it anyway, so drop the buffer. */
377 msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
378 now - p_buffer->i_pts );
379 inputDrop( p_input, p_buffer );
380 inputResamplingStop( p_input );
384 /* If the audio drift is too big then it's not worth trying to resample
386 if( start_date == VLC_TS_INVALID )
388 start_date = p_buffer->i_pts;
389 date_Set (date, start_date);
392 mtime_t drift = start_date - p_buffer->i_pts;
394 if( drift < -i_input_rate * 3 * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT )
396 msg_Warn( p_aout, "buffer way too early (%"PRId64"), clearing queue",
398 aout_OutputFlush( p_aout, false );
399 if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
400 msg_Warn( p_aout, "timing screwed, stopping resampling" );
401 inputResamplingStop( p_input );
402 p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
403 start_date = p_buffer->i_pts;
404 date_Set (date, start_date);
408 if( drift > +i_input_rate * 3 * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT )
410 msg_Warn( p_aout, "buffer way too late (%"PRId64"), dropping buffer",
412 inputDrop( p_input, p_buffer );
416 /* Run pre-filters. */
417 aout_FiltersPlay( p_input->pp_filters, p_input->i_nb_filters, &p_buffer );
421 /* Run the resampler if needed.
422 * We first need to calculate the output rate of this resampler. */
423 if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
424 ( drift < -AOUT_MAX_PTS_ADVANCE || drift > +AOUT_MAX_PTS_DELAY ) &&
425 p_input->i_nb_resamplers > 0 )
427 /* Can happen in several circumstances :
428 * 1. A problem at the input (clock drift)
429 * 2. A small pause triggered by the user
430 * 3. Some delay in the output stage, causing a loss of lip
432 * Solution : resample the buffer to avoid a scratch.
434 p_input->i_resamp_start_date = now;
435 p_input->i_resamp_start_drift = (int)-drift;
436 p_input->i_resampling_type = (drift < 0) ? AOUT_RESAMPLING_DOWN
437 : AOUT_RESAMPLING_UP;
438 msg_Warn( p_aout, (drift < 0)
439 ? "buffer too early (%"PRId64"), down-sampling"
440 : "buffer too late (%"PRId64"), up-sampling", drift );
443 if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
445 /* Resampling has been triggered previously (because of dates
446 * mismatch). We want the resampling to happen progressively so
447 * it isn't too audible to the listener. */
449 if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
450 p_input->pp_resamplers[0]->fmt_in.audio.i_rate += 2; /* Hz */
452 p_input->pp_resamplers[0]->fmt_in.audio.i_rate -= 2; /* Hz */
454 /* Check if everything is back to normal, in which case we can stop the
456 unsigned int i_nominal_rate =
457 (p_input->pp_resamplers[0] == p_input->p_playback_rate_filter)
458 ? INPUT_RATE_DEFAULT * p_input->samplerate / i_input_rate
459 : p_input->samplerate;
460 if( p_input->pp_resamplers[0]->fmt_in.audio.i_rate == i_nominal_rate )
462 p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
463 msg_Warn( p_aout, "resampling stopped after %"PRIi64" usec "
464 "(drift: %"PRIi64")",
465 now - p_input->i_resamp_start_date,
466 p_buffer->i_pts - start_date);
468 else if( abs( (int)(p_buffer->i_pts - start_date) ) <
469 abs( p_input->i_resamp_start_drift ) / 2 )
471 /* if we reduced the drift from half, then it is time to switch
472 * back the resampling direction. */
473 if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
474 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
476 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
477 p_input->i_resamp_start_drift = 0;
479 else if( p_input->i_resamp_start_drift &&
480 ( abs( (int)(p_buffer->i_pts - start_date) ) >
481 abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
483 /* If the drift is increasing and not decreasing, than something
484 * is bad. We'd better stop the resampling right now. */
485 msg_Warn( p_aout, "timing screwed, stopping resampling" );
486 inputResamplingStop( p_input );
487 p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
491 /* Actually run the resampler now. */
492 if ( p_input->i_nb_resamplers > 0 )
494 aout_FiltersPlay( p_input->pp_resamplers, p_input->i_nb_resamplers,
500 if( p_buffer->i_nb_samples <= 0 )
502 block_Release( p_buffer );
506 p_buffer->i_pts = start_date;
510 /*****************************************************************************
512 *****************************************************************************/
514 static void inputDrop( aout_input_t *p_input, block_t *p_buffer )
516 block_Release( p_buffer );
518 p_input->i_buffer_lost++;
521 static void inputResamplingStop( aout_input_t *p_input )
523 p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
524 if( p_input->i_nb_resamplers != 0 )
526 p_input->pp_resamplers[0]->fmt_in.audio.i_rate =
527 ( p_input->pp_resamplers[0] == p_input->p_playback_rate_filter )
528 ? INPUT_RATE_DEFAULT * p_input->samplerate / p_input->i_last_input_rate
529 : p_input->samplerate;
533 static vout_thread_t *RequestVout( void *p_private,
534 vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
536 audio_output_t *p_aout = p_private;
537 VLC_UNUSED(b_recycle);
538 vout_configuration_t cfg = {
545 return vout_Request( p_aout, &cfg );
548 vout_thread_t *aout_filter_RequestVout( filter_t *p_filter,
549 vout_thread_t *p_vout, video_format_t *p_fmt )
551 aout_input_t *p_input = (aout_input_t *)p_filter->p_owner;
552 aout_request_vout_t *p_request = &p_input->request_vout;
554 /* XXX: this only works from audio input */
555 /* If you want to use visualization filters from another place, you will
556 * need to add a new pf_aout_request_vout callback or store a pointer
557 * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
559 return p_request->pf_request_vout( p_request->p_private,
560 p_vout, p_fmt, p_input->b_recycle_vout );
563 static inline bool ChangeFiltersString (vlc_object_t *aout, const char *var,
564 const char *filter, bool add)
566 return aout_ChangeFilterString (aout, aout, var, filter, add);
569 static int VisualizationCallback (vlc_object_t *obj, char const *var,
570 vlc_value_t oldval, vlc_value_t newval,
573 const char *mode = newval.psz_string;
574 //aout_input_t *input = data;
579 ChangeFiltersString (obj, "audio-visual", "goom", false);
580 ChangeFiltersString (obj, "audio-visual", "visual", false);
581 ChangeFiltersString (obj, "audio-visual", "projectm", false);
582 ChangeFiltersString (obj, "audio-visual", "vsxu", false);
584 else if (!strcmp ("goom", mode))
586 ChangeFiltersString (obj, "audio-visual", "visual", false );
587 ChangeFiltersString (obj, "audio-visual", "goom", true );
588 ChangeFiltersString (obj, "audio-visual", "projectm", false );
589 ChangeFiltersString (obj, "audio-visual", "vsxu", false);
591 else if (!strcmp ("projectm", mode))
593 ChangeFiltersString (obj, "audio-visual", "visual", false);
594 ChangeFiltersString (obj, "audio-visual", "goom", false);
595 ChangeFiltersString (obj, "audio-visual", "projectm", true);
596 ChangeFiltersString (obj, "audio-visual", "vsxu", false);
598 else if (!strcmp ("vsxu", mode))
600 ChangeFiltersString (obj, "audio-visual", "visual", false);
601 ChangeFiltersString (obj, "audio-visual", "goom", false);
602 ChangeFiltersString (obj, "audio-visual", "projectm", false);
603 ChangeFiltersString (obj, "audio-visual", "vsxu", true);
607 var_Create (obj, "effect-list", VLC_VAR_STRING);
608 var_SetString (obj, "effect-list", mode);
610 ChangeFiltersString (obj, "audio-visual", "goom", false);
611 ChangeFiltersString (obj, "audio-visual", "visual", true);
612 ChangeFiltersString (obj, "audio-visual", "projectm", false);
615 /* That sucks FIXME: use "input" instead of cast */
616 aout_InputRequestRestart ((audio_output_t *)obj);
618 (void) var; (void) oldval;
622 static int EqualizerCallback (vlc_object_t *obj, char const *cmd,
623 vlc_value_t oldval, vlc_value_t newval,
626 char *mode = newval.psz_string;
627 //aout_input_t *input = data;
631 (void) cmd; (void) oldval;
633 ret = ChangeFiltersString (obj, "audio-filter", "equalizer", false);
636 var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
637 var_SetString (obj, "equalizer-preset", mode);
638 ret = ChangeFiltersString (obj, "audio-filter", "equalizer", true);
643 aout_InputRequestRestart ((audio_output_t *)obj);