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
*, aout_buffer_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
;
151 p_filter
->p_owner
= malloc( sizeof(*p_filter
->p_owner
) );
152 p_filter
->p_owner
->p_aout
= p_aout
;
153 p_filter
->p_owner
->p_input
= p_input
;
156 memcpy( &p_filter
->fmt_in
.audio
, &chain_output_format
,
157 sizeof(audio_sample_format_t
) );
158 p_filter
->fmt_in
.i_codec
= chain_output_format
.i_format
;
159 memcpy( &p_filter
->fmt_out
.audio
, &chain_output_format
,
160 sizeof(audio_sample_format_t
) );
161 p_filter
->fmt_out
.i_codec
= chain_output_format
.i_format
;
163 /* try to find the requested filter */
164 if( i_visual
== 2 ) /* this can only be a visualization module */
166 p_filter
->p_module
= module_need( p_filter
, "visualization2",
169 else /* this can be a audio filter module as well as a visualization module */
171 p_filter
->p_module
= module_need( p_filter
, "audio filter",
174 if ( p_filter
->p_module
== NULL
)
176 /* if the filter requested a special format, retry */
177 if ( !( AOUT_FMTS_IDENTICAL( &p_filter
->fmt_in
.audio
,
178 &chain_input_format
)
179 && AOUT_FMTS_IDENTICAL( &p_filter
->fmt_out
.audio
,
180 &chain_output_format
) ) )
182 aout_FormatPrepare( &p_filter
->fmt_in
.audio
);
183 aout_FormatPrepare( &p_filter
->fmt_out
.audio
);
184 p_filter
->p_module
= module_need( p_filter
,
188 /* try visual filters */
191 memcpy( &p_filter
->fmt_in
.audio
, &chain_output_format
,
192 sizeof(audio_sample_format_t
) );
193 memcpy( &p_filter
->fmt_out
.audio
, &chain_output_format
,
194 sizeof(audio_sample_format_t
) );
195 p_filter
->p_module
= module_need( p_filter
,
203 if ( p_filter
->p_module
== NULL
)
205 msg_Err( p_aout
, "cannot add user filter %s (skipped)",
208 free( p_filter
->p_owner
);
209 vlc_object_release( p_filter
);
211 psz_parser
= psz_next
;
215 /* complete the filter chain if necessary */
216 if ( aout_FiltersCreatePipeline( p_aout
, p_input
->pp_filters
,
217 &p_input
->i_nb_filters
,
219 &p_filter
->fmt_in
.audio
) < 0 )
221 msg_Err( p_aout
, "cannot add user filter %s (skipped)",
224 module_unneed( p_filter
, p_filter
->p_module
);
225 free( p_filter
->p_owner
);
226 vlc_object_release( p_filter
);
228 psz_parser
= psz_next
;
233 p_input
->pp_filters
[p_input
->i_nb_filters
++] = p_filter
;
234 memcpy( &chain_input_format
, &p_filter
->fmt_out
.audio
,
235 sizeof( audio_sample_format_t
) );
237 if( i_visual
== 0 ) /* scaletempo */
238 p_input
->p_playback_rate_filter
= p_filter
;
240 /* next filter if any */
241 psz_parser
= psz_next
;
246 free( psz_scaletempo
);
248 /* complete the filter chain if necessary */
249 if ( aout_FiltersCreatePipeline( p_aout
, p_input
->pp_filters
,
250 &p_input
->i_nb_filters
,
252 &chain_output_format
) < 0 )
254 msg_Err (p_aout
, "cannot setup filtering pipeline");
258 /* Create resamplers. */
259 if (AOUT_FMT_LINEAR(outfmt
))
261 chain_output_format
.i_rate
= (__MAX(p_input
->samplerate
,
263 * (100 + AOUT_MAX_RESAMPLING
)) / 100;
264 if ( chain_output_format
.i_rate
== outfmt
->i_rate
)
266 /* Just in case... */
267 chain_output_format
.i_rate
++;
269 if (aout_FiltersCreatePipeline (p_aout
, p_input
->pp_resamplers
,
270 &p_input
->i_nb_resamplers
,
271 &chain_output_format
, outfmt
) < 0)
273 msg_Err (p_aout
, "cannot setup a resampling pipeline");
277 /* Setup the initial rate of the resampler */
278 p_input
->pp_resamplers
[0]->fmt_in
.audio
.i_rate
= p_input
->samplerate
;
280 p_input
->i_resampling_type
= AOUT_RESAMPLING_NONE
;
282 if( ! p_input
->p_playback_rate_filter
&& p_input
->i_nb_resamplers
> 0 )
284 p_input
->p_playback_rate_filter
= p_input
->pp_resamplers
[0];
288 p_input
->i_last_input_rate
= INPUT_RATE_DEFAULT
;
289 p_input
->i_buffer_lost
= 0;
293 aout_FiltersDestroyPipeline( p_input
->pp_filters
, p_input
->i_nb_filters
);
294 aout_FiltersDestroyPipeline( p_input
->pp_resamplers
,
295 p_input
->i_nb_resamplers
);
300 /*****************************************************************************
301 * aout_InputDelete : delete an input
302 *****************************************************************************
303 * This function must be entered with the mixer lock.
304 *****************************************************************************/
305 int aout_InputDelete( audio_output_t
* p_aout
, aout_input_t
* p_input
)
307 var_DelCallback (p_aout
, "equalizer", EqualizerCallback
, p_input
);
308 var_DelCallback (p_aout
, "visual", VisualizationCallback
, p_input
);
310 /* XXX We need to update b_recycle_vout before calling aout_FiltersDestroyPipeline.
311 * FIXME They can be a race condition if audio-visual is updated between
312 * aout_InputDelete and aout_InputNew.
314 char *psz_visual
= var_GetString( p_aout
, "audio-visual");
315 p_input
->b_recycle_vout
= psz_visual
&& *psz_visual
;
318 aout_FiltersDestroyPipeline( p_input
->pp_filters
, p_input
->i_nb_filters
);
319 p_input
->i_nb_filters
= 0;
320 aout_FiltersDestroyPipeline( p_input
->pp_resamplers
,
321 p_input
->i_nb_resamplers
);
322 p_input
->i_nb_resamplers
= 0;
327 /*****************************************************************************
328 * aout_InputPlay : play a buffer
329 *****************************************************************************
330 * This function must be entered with the input lock.
331 *****************************************************************************/
332 /* XXX Do not activate it !! */
333 //#define AOUT_PROCESS_BEFORE_CHEKS
334 block_t
*aout_InputPlay(audio_output_t
*p_aout
, aout_input_t
*p_input
,
335 block_t
*p_buffer
, int i_input_rate
, date_t
*date
)
339 aout_assert_locked( p_aout
);
341 if( i_input_rate
!= INPUT_RATE_DEFAULT
&& p_input
->p_playback_rate_filter
== NULL
)
343 inputDrop( p_input
, p_buffer
);
347 #ifdef AOUT_PROCESS_BEFORE_CHEKS
348 /* Run pre-filters. */
349 aout_FiltersPlay( p_aout
, p_input
->pp_filters
, p_input
->i_nb_filters
,
354 /* Actually run the resampler now. */
355 if ( p_input
->i_nb_resamplers
> 0 )
357 const mtime_t i_date
= p_buffer
->i_pts
;
358 aout_FiltersPlay( p_aout
, p_input
->pp_resamplers
,
359 p_input
->i_nb_resamplers
,
365 if( p_buffer
->i_nb_samples
<= 0 )
367 block_Release( p_buffer
);
372 /* Handle input rate change, but keep drift correction */
373 if( i_input_rate
!= p_input
->i_last_input_rate
)
375 unsigned int * const pi_rate
= &p_input
->p_playback_rate_filter
->fmt_in
.audio
.i_rate
;
376 #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
377 const int i_delta
= *pi_rate
- F(p_input
->samplerate
,p_input
->i_last_input_rate
);
378 *pi_rate
= F(p_input
->samplerate
+ i_delta
, i_input_rate
);
380 p_input
->i_last_input_rate
= i_input_rate
;
383 mtime_t now
= mdate();
385 /* We don't care if someone changes the start date behind our back after
386 * this. We'll deal with that when pushing the buffer, and compensate
387 * with the next incoming buffer. */
388 start_date
= date_Get (date
);
390 if ( start_date
!= VLC_TS_INVALID
&& start_date
< now
)
392 /* The decoder is _very_ late. This can only happen if the user
393 * pauses the stream (or if the decoder is buggy, which cannot
395 msg_Warn( p_aout
, "computed PTS is out of range (%"PRId64
"), "
396 "clearing out", now
- start_date
);
397 aout_OutputFlush( p_aout
, false );
398 if ( p_input
->i_resampling_type
!= AOUT_RESAMPLING_NONE
)
399 msg_Warn( p_aout
, "timing screwed, stopping resampling" );
400 inputResamplingStop( p_input
);
401 p_buffer
->i_flags
|= BLOCK_FLAG_DISCONTINUITY
;
402 start_date
= VLC_TS_INVALID
;
405 if ( p_buffer
->i_pts
< now
+ AOUT_MIN_PREPARE_TIME
)
407 /* The decoder gives us f*cked up PTS. It's its business, but we
408 * can't present it anyway, so drop the buffer. */
409 msg_Warn( p_aout
, "PTS is out of range (%"PRId64
"), dropping buffer",
410 now
- p_buffer
->i_pts
);
411 inputDrop( p_input
, p_buffer
);
412 inputResamplingStop( p_input
);
416 /* If the audio drift is too big then it's not worth trying to resample
418 if( start_date
== VLC_TS_INVALID
)
420 start_date
= p_buffer
->i_pts
;
421 date_Set (date
, start_date
);
424 mtime_t drift
= start_date
- p_buffer
->i_pts
;
426 if( drift
< -i_input_rate
* 3 * AOUT_MAX_PTS_ADVANCE
/ INPUT_RATE_DEFAULT
)
428 msg_Warn( p_aout
, "buffer way too early (%"PRId64
"), clearing queue",
430 aout_OutputFlush( p_aout
, false );
431 if ( p_input
->i_resampling_type
!= AOUT_RESAMPLING_NONE
)
432 msg_Warn( p_aout
, "timing screwed, stopping resampling" );
433 inputResamplingStop( p_input
);
434 p_buffer
->i_flags
|= BLOCK_FLAG_DISCONTINUITY
;
435 start_date
= p_buffer
->i_pts
;
436 date_Set (date
, start_date
);
440 if( drift
> +i_input_rate
* 3 * AOUT_MAX_PTS_DELAY
/ INPUT_RATE_DEFAULT
)
442 msg_Warn( p_aout
, "buffer way too late (%"PRId64
"), dropping buffer",
444 inputDrop( p_input
, p_buffer
);
448 #ifndef AOUT_PROCESS_BEFORE_CHEKS
449 /* Run pre-filters. */
450 aout_FiltersPlay( p_input
->pp_filters
, p_input
->i_nb_filters
, &p_buffer
);
455 /* Run the resampler if needed.
456 * We first need to calculate the output rate of this resampler. */
457 if ( ( p_input
->i_resampling_type
== AOUT_RESAMPLING_NONE
) &&
458 ( drift
< -AOUT_MAX_PTS_ADVANCE
|| drift
> +AOUT_MAX_PTS_DELAY
) &&
459 p_input
->i_nb_resamplers
> 0 )
461 /* Can happen in several circumstances :
462 * 1. A problem at the input (clock drift)
463 * 2. A small pause triggered by the user
464 * 3. Some delay in the output stage, causing a loss of lip
466 * Solution : resample the buffer to avoid a scratch.
468 p_input
->i_resamp_start_date
= now
;
469 p_input
->i_resamp_start_drift
= (int)-drift
;
470 p_input
->i_resampling_type
= (drift
< 0) ? AOUT_RESAMPLING_DOWN
471 : AOUT_RESAMPLING_UP
;
472 msg_Warn( p_aout
, (drift
< 0)
473 ? "buffer too early (%"PRId64
"), down-sampling"
474 : "buffer too late (%"PRId64
"), up-sampling", drift
);
477 if ( p_input
->i_resampling_type
!= AOUT_RESAMPLING_NONE
)
479 /* Resampling has been triggered previously (because of dates
480 * mismatch). We want the resampling to happen progressively so
481 * it isn't too audible to the listener. */
483 if( p_input
->i_resampling_type
== AOUT_RESAMPLING_UP
)
484 p_input
->pp_resamplers
[0]->fmt_in
.audio
.i_rate
+= 2; /* Hz */
486 p_input
->pp_resamplers
[0]->fmt_in
.audio
.i_rate
-= 2; /* Hz */
488 /* Check if everything is back to normal, in which case we can stop the
490 unsigned int i_nominal_rate
=
491 (p_input
->pp_resamplers
[0] == p_input
->p_playback_rate_filter
)
492 ? INPUT_RATE_DEFAULT
* p_input
->samplerate
/ i_input_rate
493 : p_input
->samplerate
;
494 if( p_input
->pp_resamplers
[0]->fmt_in
.audio
.i_rate
== i_nominal_rate
)
496 p_input
->i_resampling_type
= AOUT_RESAMPLING_NONE
;
497 msg_Warn( p_aout
, "resampling stopped after %"PRIi64
" usec "
498 "(drift: %"PRIi64
")",
499 now
- p_input
->i_resamp_start_date
,
500 p_buffer
->i_pts
- start_date
);
502 else if( abs( (int)(p_buffer
->i_pts
- start_date
) ) <
503 abs( p_input
->i_resamp_start_drift
) / 2 )
505 /* if we reduced the drift from half, then it is time to switch
506 * back the resampling direction. */
507 if( p_input
->i_resampling_type
== AOUT_RESAMPLING_UP
)
508 p_input
->i_resampling_type
= AOUT_RESAMPLING_DOWN
;
510 p_input
->i_resampling_type
= AOUT_RESAMPLING_UP
;
511 p_input
->i_resamp_start_drift
= 0;
513 else if( p_input
->i_resamp_start_drift
&&
514 ( abs( (int)(p_buffer
->i_pts
- start_date
) ) >
515 abs( p_input
->i_resamp_start_drift
) * 3 / 2 ) )
517 /* If the drift is increasing and not decreasing, than something
518 * is bad. We'd better stop the resampling right now. */
519 msg_Warn( p_aout
, "timing screwed, stopping resampling" );
520 inputResamplingStop( p_input
);
521 p_buffer
->i_flags
|= BLOCK_FLAG_DISCONTINUITY
;
525 #ifndef AOUT_PROCESS_BEFORE_CHEKS
526 /* Actually run the resampler now. */
527 if ( p_input
->i_nb_resamplers
> 0 )
529 aout_FiltersPlay( p_input
->pp_resamplers
, p_input
->i_nb_resamplers
,
535 if( p_buffer
->i_nb_samples
<= 0 )
537 block_Release( p_buffer
);
542 p_buffer
->i_pts
= start_date
;
546 /*****************************************************************************
548 *****************************************************************************/
550 static void inputDrop( aout_input_t
*p_input
, aout_buffer_t
*p_buffer
)
552 aout_BufferFree( p_buffer
);
554 p_input
->i_buffer_lost
++;
557 static void inputResamplingStop( aout_input_t
*p_input
)
559 p_input
->i_resampling_type
= AOUT_RESAMPLING_NONE
;
560 if( p_input
->i_nb_resamplers
!= 0 )
562 p_input
->pp_resamplers
[0]->fmt_in
.audio
.i_rate
=
563 ( p_input
->pp_resamplers
[0] == p_input
->p_playback_rate_filter
)
564 ? INPUT_RATE_DEFAULT
* p_input
->samplerate
/ p_input
->i_last_input_rate
565 : p_input
->samplerate
;
569 static vout_thread_t
*RequestVout( void *p_private
,
570 vout_thread_t
*p_vout
, video_format_t
*p_fmt
, bool b_recycle
)
572 audio_output_t
*p_aout
= p_private
;
573 VLC_UNUSED(b_recycle
);
574 vout_configuration_t cfg
= {
581 return vout_Request( p_aout
, &cfg
);
584 vout_thread_t
*aout_filter_RequestVout( filter_t
*p_filter
,
585 vout_thread_t
*p_vout
, video_format_t
*p_fmt
)
587 aout_input_t
*p_input
= p_filter
->p_owner
->p_input
;
588 aout_request_vout_t
*p_request
= &p_input
->request_vout
;
590 /* XXX: this only works from audio input */
591 /* If you want to use visualization filters from another place, you will
592 * need to add a new pf_aout_request_vout callback or store a pointer
593 * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
595 return p_request
->pf_request_vout( p_request
->p_private
,
596 p_vout
, p_fmt
, p_input
->b_recycle_vout
);
599 static inline bool ChangeFiltersString (vlc_object_t
*aout
, const char *var
,
600 const char *filter
, bool add
)
602 return aout_ChangeFilterString (aout
, aout
, var
, filter
, add
);
605 static int VisualizationCallback (vlc_object_t
*obj
, char const *var
,
606 vlc_value_t oldval
, vlc_value_t newval
,
609 const char *mode
= newval
.psz_string
;
610 //aout_input_t *input = data;
615 ChangeFiltersString (obj
, "audio-visual", "goom", false);
616 ChangeFiltersString (obj
, "audio-visual", "visual", false);
617 ChangeFiltersString (obj
, "audio-visual", "projectm", false);
619 else if (!strcmp ("goom", mode
))
621 ChangeFiltersString (obj
, "audio-visual", "visual", false );
622 ChangeFiltersString (obj
, "audio-visual", "goom", true );
623 ChangeFiltersString (obj
, "audio-visual", "projectm", false );
625 else if (!strcmp ("projectm", mode
))
627 ChangeFiltersString (obj
, "audio-visual", "visual", false);
628 ChangeFiltersString (obj
, "audio-visual", "goom", false);
629 ChangeFiltersString (obj
, "audio-visual", "projectm", true);
633 var_Create (obj
, "effect-list", VLC_VAR_STRING
);
634 var_SetString (obj
, "effect-list", mode
);
636 ChangeFiltersString (obj
, "audio-visual", "goom", false);
637 ChangeFiltersString (obj
, "audio-visual", "visual", true);
638 ChangeFiltersString (obj
, "audio-visual", "projectm", false);
641 /* That sucks FIXME: use "input" instead of cast */
642 aout_InputRequestRestart ((audio_output_t
*)obj
);
644 (void) var
; (void) oldval
;
648 static int EqualizerCallback (vlc_object_t
*obj
, char const *cmd
,
649 vlc_value_t oldval
, vlc_value_t newval
,
652 char *mode
= newval
.psz_string
;
653 //aout_input_t *input = data;
657 (void) cmd
; (void) oldval
;
659 ret
= ChangeFiltersString (obj
, "audio-filter", "equalizer", false);
662 var_Create (obj
, "equalizer-preset", VLC_VAR_STRING
);
663 var_SetString (obj
, "equalizer-preset", mode
);
664 ret
= ChangeFiltersString (obj
, "audio-filter", "equalizer", true);
669 aout_InputRequestRestart ((audio_output_t
*)obj
);