Fixed a crash caused by yadif deinterlacer on Windows XP
[vlc/solaris.git] / src / audio_output / input.c
blob42b67b7b41177493a84fabab97a4744b28026fcc
1 /*****************************************************************************
2 * input.c : internal management of input streams for the audio output
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
5 * $Id$
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 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <assert.h>
38 #include <vlc_input.h>
39 #include <vlc_vout.h> /* for vout_Request */
40 #include <vlc_modules.h>
41 #include <vlc_aout.h>
42 #include <vlc_filter.h>
43 #include <libvlc.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))
68 return 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;
75 /* */
76 if( p_request_vout )
78 p_input->request_vout = *p_request_vout;
80 else
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);
109 i_visual++)
111 char *psz_next = NULL;
112 char *psz_parser = ppsz_array[i_visual];
114 if( psz_parser == NULL || !*psz_parser )
115 continue;
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 );
124 break;
127 while( *psz_parser == ' ' && *psz_parser == ':' )
129 psz_parser++;
131 if( ( psz_next = strchr( psz_parser , ':' ) ) )
133 *psz_next++ = '\0';
135 if( *psz_parser =='\0' )
137 break;
140 /* Create a VLC object */
141 p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
142 "audio filter" );
143 if( p_filter == NULL )
145 msg_Err( p_aout, "cannot add user filter %s (skipped)",
146 psz_parser );
147 psz_parser = psz_next;
148 continue;
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;
155 /* request format */
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",
167 psz_parser, true );
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",
172 psz_parser, true );
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,
185 "audio filter",
186 psz_parser, true );
188 /* try visual filters */
189 else
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,
196 "visualization2",
197 psz_parser, true );
202 /* failure */
203 if ( p_filter->p_module == NULL )
205 msg_Err( p_aout, "cannot add user filter %s (skipped)",
206 psz_parser );
208 free( p_filter->p_owner );
209 vlc_object_release( p_filter );
211 psz_parser = psz_next;
212 continue;
215 /* complete the filter chain if necessary */
216 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
217 &p_input->i_nb_filters,
218 &chain_input_format,
219 &p_filter->fmt_in.audio ) < 0 )
221 msg_Err( p_aout, "cannot add user filter %s (skipped)",
222 psz_parser );
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;
229 continue;
232 /* success */
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;
244 free( psz_visual );
245 free( psz_filters );
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,
251 &chain_input_format,
252 &chain_output_format ) < 0 )
254 msg_Err (p_aout, "cannot setup filtering pipeline");
255 goto error;
258 /* Create resamplers. */
259 if (AOUT_FMT_LINEAR(outfmt))
261 chain_output_format.i_rate = (__MAX(p_input->samplerate,
262 outfmt->i_rate)
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");
274 goto error;
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];
287 /* Success */
288 p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
289 p_input->i_buffer_lost = 0;
290 return p_input;
292 error:
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 );
296 free (p_input);
297 return NULL;
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;
316 free( 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;
324 return 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 )
337 mtime_t start_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 );
344 return NULL;
347 #ifdef AOUT_PROCESS_BEFORE_CHEKS
348 /* Run pre-filters. */
349 aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
350 &p_buffer );
351 if( !p_buffer )
352 return NULL;
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,
360 &p_buffer );
363 if( !p_buffer )
364 return NULL;
365 if( p_buffer->i_nb_samples <= 0 )
367 block_Release( p_buffer );
368 return NULL;
370 #endif
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);
379 #undef F
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
394 * happen :). */
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 );
413 return NULL;
416 /* If the audio drift is too big then it's not worth trying to resample
417 * the audio. */
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",
429 drift );
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);
437 drift = 0;
439 else
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",
443 drift );
444 inputDrop( p_input, p_buffer );
445 return NULL;
448 #ifndef AOUT_PROCESS_BEFORE_CHEKS
449 /* Run pre-filters. */
450 aout_FiltersPlay( p_input->pp_filters, p_input->i_nb_filters, &p_buffer );
451 if( !p_buffer )
452 return NULL;
453 #endif
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
465 * synchronization
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 */
485 else
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
489 * resampling */
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;
509 else
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,
530 &p_buffer );
533 if( !p_buffer )
534 return NULL;
535 if( p_buffer->i_nb_samples <= 0 )
537 block_Release( p_buffer );
538 return NULL;
540 #endif
542 p_buffer->i_pts = start_date;
543 return p_buffer;
546 /*****************************************************************************
547 * static functions
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 = {
575 .vout = p_vout,
576 .input = NULL,
577 .change_fmt = true,
578 .fmt = p_fmt,
579 .dpb_size = 1,
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,
607 void *data)
609 const char *mode = newval.psz_string;
610 //aout_input_t *input = data;
611 (void) data;
613 if (!*mode)
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);
631 else
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;
645 return VLC_SUCCESS;
648 static int EqualizerCallback (vlc_object_t *obj, char const *cmd,
649 vlc_value_t oldval, vlc_value_t newval,
650 void *data)
652 char *mode = newval.psz_string;
653 //aout_input_t *input = data;
654 bool ret;
656 (void) data;
657 (void) cmd; (void) oldval;
658 if (!*mode)
659 ret = ChangeFiltersString (obj, "audio-filter", "equalizer", false);
660 else
662 var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
663 var_SetString (obj, "equalizer-preset", mode);
664 ret = ChangeFiltersString (obj, "audio-filter", "equalizer", true);
667 /* That sucks */
668 if (ret)
669 aout_InputRequestRestart ((audio_output_t *)obj);
670 return VLC_SUCCESS;