1 /*****************************************************************************
2 * common.c : audio output management of common data structures
3 *****************************************************************************
4 * Copyright (C) 2002-2007 the VideoLAN team
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
36 #include "aout_internal.h"
40 * Instances management (internal and external)
43 #define AOUT_ASSERT_FIFO_LOCKED aout_assert_fifo_locked(p_aout, p_fifo)
44 static inline void aout_assert_fifo_locked( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
50 if( p_fifo
== &p_aout
->output
.fifo
)
51 vlc_assert_locked( &p_aout
->output_fifo_lock
);
55 for( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
57 if( p_fifo
== &p_aout
->pp_inputs
[i
]->mixer
.fifo
)
59 vlc_assert_locked( &p_aout
->input_fifos_lock
);
63 if( i
== p_aout
->i_nb_inputs
)
64 vlc_assert_locked( &p_aout
->mixer_lock
);
73 static void aout_Destructor( vlc_object_t
* p_this
);
75 /*****************************************************************************
76 * aout_New: initialize aout structure
77 *****************************************************************************/
78 aout_instance_t
* __aout_New( vlc_object_t
* p_parent
)
80 aout_instance_t
* p_aout
;
82 /* Allocate descriptor. */
83 p_aout
= vlc_custom_create( p_parent
, sizeof( *p_aout
), VLC_OBJECT_AOUT
,
90 /* Initialize members. */
91 vlc_mutex_init( &p_aout
->input_fifos_lock
);
92 vlc_mutex_init( &p_aout
->mixer_lock
);
93 vlc_mutex_init( &p_aout
->volume_vars_lock
);
94 vlc_mutex_init( &p_aout
->output_fifo_lock
);
95 p_aout
->i_nb_inputs
= 0;
96 p_aout
->mixer_multiplier
= 1.0;
97 p_aout
->p_mixer
= NULL
;
98 p_aout
->output
.b_error
= 1;
99 p_aout
->output
.b_starving
= 1;
101 var_Create( p_aout
, "intf-change", VLC_VAR_BOOL
);
102 var_SetBool( p_aout
, "intf-change", true );
104 vlc_object_set_destructor( p_aout
, aout_Destructor
);
106 vlc_object_attach( p_aout
, p_parent
);
111 /*****************************************************************************
112 * aout_Destructor: destroy aout structure
113 *****************************************************************************/
114 static void aout_Destructor( vlc_object_t
* p_this
)
116 aout_instance_t
* p_aout
= (aout_instance_t
*)p_this
;
117 vlc_mutex_destroy( &p_aout
->input_fifos_lock
);
118 vlc_mutex_destroy( &p_aout
->mixer_lock
);
119 vlc_mutex_destroy( &p_aout
->volume_vars_lock
);
120 vlc_mutex_destroy( &p_aout
->output_fifo_lock
);
123 /* Lock ordering rules:
125 * Vars Mixer Input IFIFO OFIFO (< Inner lock)
126 * Vars No! Yes Yes Yes Yes
127 * Mixer No! No! Yes Yes Yes
128 * Input No! No! No! Yes Yes
129 * In FIFOs No! No! No! No! Yes
130 * Out FIFOs No! No! No! No! No!
135 static __thread
unsigned aout_locks
= 0;
137 void aout_lock (unsigned i
)
142 case VOLUME_VARS_LOCK
:
146 allowed
= VOLUME_VARS_LOCK
;
149 allowed
= VOLUME_VARS_LOCK
|MIXER_LOCK
;
151 case INPUT_FIFO_LOCK
:
152 allowed
= VOLUME_VARS_LOCK
|MIXER_LOCK
|INPUT_LOCK
;
154 case OUTPUT_FIFO_LOCK
:
155 allowed
= VOLUME_VARS_LOCK
|MIXER_LOCK
|INPUT_LOCK
|INPUT_FIFO_LOCK
;
161 if (aout_locks
& ~allowed
)
163 fprintf (stderr
, "Illegal audio lock transition (%x -> %x)\n",
164 aout_locks
, aout_locks
|i
);
171 void aout_unlock (unsigned i
)
173 assert (aout_locks
& i
);
179 * Formats management (internal and external)
182 /*****************************************************************************
183 * aout_FormatNbChannels : return the number of channels
184 *****************************************************************************/
185 unsigned int aout_FormatNbChannels( const audio_sample_format_t
* p_format
)
187 static const uint32_t pi_channels
[] =
188 { AOUT_CHAN_CENTER
, AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
,
189 AOUT_CHAN_REARCENTER
, AOUT_CHAN_REARLEFT
, AOUT_CHAN_REARRIGHT
,
190 AOUT_CHAN_MIDDLELEFT
, AOUT_CHAN_MIDDLERIGHT
, AOUT_CHAN_LFE
};
191 unsigned int i_nb
= 0, i
;
193 for ( i
= 0; i
< sizeof(pi_channels
)/sizeof(uint32_t); i
++ )
195 if ( p_format
->i_physical_channels
& pi_channels
[i
] ) i_nb
++;
201 /*****************************************************************************
202 * aout_BitsPerSample : get the number of bits per sample
203 *****************************************************************************/
204 unsigned int aout_BitsPerSample( vlc_fourcc_t i_format
)
206 switch( vlc_fourcc_GetCodec( AUDIO_ES
, i_format
) )
236 /* For these formats the caller has to indicate the parameters
242 /*****************************************************************************
243 * aout_FormatPrepare : compute the number of bytes per frame & frame length
244 *****************************************************************************/
245 void aout_FormatPrepare( audio_sample_format_t
* p_format
)
247 p_format
->i_channels
= aout_FormatNbChannels( p_format
);
248 p_format
->i_bitspersample
= aout_BitsPerSample( p_format
->i_format
);
249 if( p_format
->i_bitspersample
> 0 )
251 p_format
->i_bytes_per_frame
= ( p_format
->i_bitspersample
/ 8 )
252 * aout_FormatNbChannels( p_format
);
253 p_format
->i_frame_length
= 1;
257 /*****************************************************************************
258 * aout_FormatPrintChannels : print a channel in a human-readable form
259 *****************************************************************************/
260 const char * aout_FormatPrintChannels( const audio_sample_format_t
* p_format
)
262 switch ( p_format
->i_physical_channels
& AOUT_CHAN_PHYSMASK
)
265 case AOUT_CHAN_RIGHT
:
266 case AOUT_CHAN_CENTER
:
267 if ( (p_format
->i_original_channels
& AOUT_CHAN_CENTER
)
268 || (p_format
->i_original_channels
269 & (AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
)) )
271 else if ( p_format
->i_original_channels
& AOUT_CHAN_LEFT
)
274 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
:
275 if ( p_format
->i_original_channels
& AOUT_CHAN_REVERSESTEREO
)
277 if ( p_format
->i_original_channels
& AOUT_CHAN_DOLBYSTEREO
)
278 return "Dolby/Reverse";
279 return "Stereo/Reverse";
283 if ( p_format
->i_original_channels
& AOUT_CHAN_DOLBYSTEREO
)
285 else if ( p_format
->i_original_channels
& AOUT_CHAN_DUALMONO
)
287 else if ( p_format
->i_original_channels
== AOUT_CHAN_CENTER
)
288 return "Stereo/Mono";
289 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_RIGHT
) )
290 return "Stereo/Left";
291 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_LEFT
) )
292 return "Stereo/Right";
295 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
:
297 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_REARCENTER
:
299 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
300 | AOUT_CHAN_REARCENTER
:
302 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
303 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
:
305 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
306 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
:
308 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
309 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
:
311 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
312 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
:
315 case AOUT_CHAN_CENTER
| AOUT_CHAN_LFE
:
316 if ( (p_format
->i_original_channels
& AOUT_CHAN_CENTER
)
317 || (p_format
->i_original_channels
318 & (AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
)) )
320 else if ( p_format
->i_original_channels
& AOUT_CHAN_LEFT
)
323 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_LFE
:
324 if ( p_format
->i_original_channels
& AOUT_CHAN_DOLBYSTEREO
)
326 else if ( p_format
->i_original_channels
& AOUT_CHAN_DUALMONO
)
327 return "Dual-mono/LFE";
328 else if ( p_format
->i_original_channels
== AOUT_CHAN_CENTER
)
330 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_RIGHT
) )
331 return "Stereo/Left/LFE";
332 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_LEFT
) )
333 return "Stereo/Right/LFE";
335 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
| AOUT_CHAN_LFE
:
337 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_REARCENTER
340 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
341 | AOUT_CHAN_REARCENTER
| AOUT_CHAN_LFE
:
343 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
344 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_LFE
:
346 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
347 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
| AOUT_CHAN_LFE
:
349 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
350 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_LFE
:
352 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
353 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
| AOUT_CHAN_LFE
:
355 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
356 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_MIDDLELEFT
357 | AOUT_CHAN_MIDDLERIGHT
:
359 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
360 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_MIDDLELEFT
361 | AOUT_CHAN_MIDDLERIGHT
| AOUT_CHAN_LFE
:
368 /*****************************************************************************
369 * aout_FormatPrint : print a format in a human-readable form
370 *****************************************************************************/
371 void aout_FormatPrint( aout_instance_t
* p_aout
, const char * psz_text
,
372 const audio_sample_format_t
* p_format
)
374 msg_Dbg( p_aout
, "%s '%4.4s' %d Hz %s frame=%d samples/%d bytes", psz_text
,
375 (char *)&p_format
->i_format
, p_format
->i_rate
,
376 aout_FormatPrintChannels( p_format
),
377 p_format
->i_frame_length
, p_format
->i_bytes_per_frame
);
380 /*****************************************************************************
381 * aout_FormatsPrint : print two formats in a human-readable form
382 *****************************************************************************/
383 void aout_FormatsPrint( aout_instance_t
* p_aout
, const char * psz_text
,
384 const audio_sample_format_t
* p_format1
,
385 const audio_sample_format_t
* p_format2
)
387 msg_Dbg( p_aout
, "%s '%4.4s'->'%4.4s' %d Hz->%d Hz %s->%s",
389 (char *)&p_format1
->i_format
, (char *)&p_format2
->i_format
,
390 p_format1
->i_rate
, p_format2
->i_rate
,
391 aout_FormatPrintChannels( p_format1
),
392 aout_FormatPrintChannels( p_format2
) );
397 * FIFO management (internal) - please understand that solving race conditions
398 * is _your_ job, ie. in the audio output you should own the mixer lock
399 * before calling any of these functions.
402 /*****************************************************************************
403 * aout_FifoInit : initialize the members of a FIFO
404 *****************************************************************************/
405 void aout_FifoInit( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
408 AOUT_ASSERT_FIFO_LOCKED
;
412 msg_Err( p_aout
, "initialising fifo with zero divider" );
415 p_fifo
->p_first
= NULL
;
416 p_fifo
->pp_last
= &p_fifo
->p_first
;
417 date_Init( &p_fifo
->end_date
, i_rate
, 1 );
420 /*****************************************************************************
421 * aout_FifoPush : push a packet into the FIFO
422 *****************************************************************************/
423 void aout_FifoPush( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
424 aout_buffer_t
* p_buffer
)
427 AOUT_ASSERT_FIFO_LOCKED
;
429 *p_fifo
->pp_last
= p_buffer
;
430 p_fifo
->pp_last
= &p_buffer
->p_next
;
431 *p_fifo
->pp_last
= NULL
;
432 /* Enforce the continuity of the stream. */
433 if ( date_Get( &p_fifo
->end_date
) )
435 p_buffer
->i_pts
= date_Get( &p_fifo
->end_date
);
436 p_buffer
->i_length
= date_Increment( &p_fifo
->end_date
,
437 p_buffer
->i_nb_samples
);
438 p_buffer
->i_length
-= p_buffer
->i_pts
;
442 date_Set( &p_fifo
->end_date
, p_buffer
->i_pts
+ p_buffer
->i_length
);
446 /*****************************************************************************
447 * aout_FifoSet : set end_date and trash all buffers (because they aren't
449 *****************************************************************************/
450 void aout_FifoSet( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
453 aout_buffer_t
* p_buffer
;
455 AOUT_ASSERT_FIFO_LOCKED
;
457 date_Set( &p_fifo
->end_date
, date
);
458 p_buffer
= p_fifo
->p_first
;
459 while ( p_buffer
!= NULL
)
461 aout_buffer_t
* p_next
= p_buffer
->p_next
;
462 aout_BufferFree( p_buffer
);
465 p_fifo
->p_first
= NULL
;
466 p_fifo
->pp_last
= &p_fifo
->p_first
;
469 /*****************************************************************************
470 * aout_FifoMoveDates : Move forwards or backwards all dates in the FIFO
471 *****************************************************************************/
472 void aout_FifoMoveDates( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
475 aout_buffer_t
* p_buffer
;
477 AOUT_ASSERT_FIFO_LOCKED
;
479 date_Move( &p_fifo
->end_date
, difference
);
480 p_buffer
= p_fifo
->p_first
;
481 while ( p_buffer
!= NULL
)
483 p_buffer
->i_pts
+= difference
;
484 p_buffer
= p_buffer
->p_next
;
488 /*****************************************************************************
489 * aout_FifoNextStart : return the current end_date
490 *****************************************************************************/
491 mtime_t
aout_FifoNextStart( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
494 AOUT_ASSERT_FIFO_LOCKED
;
495 return date_Get( &p_fifo
->end_date
);
498 /*****************************************************************************
499 * aout_FifoFirstDate : return the playing date of the first buffer in the
501 *****************************************************************************/
502 mtime_t
aout_FifoFirstDate( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
505 AOUT_ASSERT_FIFO_LOCKED
;
506 return p_fifo
->p_first
? p_fifo
->p_first
->i_pts
: 0;
509 /*****************************************************************************
510 * aout_FifoPop : get the next buffer out of the FIFO
511 *****************************************************************************/
512 aout_buffer_t
* aout_FifoPop( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
514 aout_buffer_t
* p_buffer
;
516 AOUT_ASSERT_FIFO_LOCKED
;
518 p_buffer
= p_fifo
->p_first
;
519 if ( p_buffer
== NULL
) return NULL
;
520 p_fifo
->p_first
= p_buffer
->p_next
;
521 if ( p_fifo
->p_first
== NULL
)
523 p_fifo
->pp_last
= &p_fifo
->p_first
;
529 /*****************************************************************************
530 * aout_FifoDestroy : destroy a FIFO and its buffers
531 *****************************************************************************/
532 void aout_FifoDestroy( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
534 aout_buffer_t
* p_buffer
;
536 AOUT_ASSERT_FIFO_LOCKED
;
538 p_buffer
= p_fifo
->p_first
;
539 while ( p_buffer
!= NULL
)
541 aout_buffer_t
* p_next
= p_buffer
->p_next
;
542 aout_BufferFree( p_buffer
);
546 p_fifo
->p_first
= NULL
;
547 p_fifo
->pp_last
= &p_fifo
->p_first
;
550 /*****************************************************************************
551 * aout_CheckChannelReorder : Check if we need to do some channel re-ordering
552 *****************************************************************************/
553 int aout_CheckChannelReorder( const uint32_t *pi_chan_order_in
,
554 const uint32_t *pi_chan_order_out
,
555 uint32_t i_channel_mask
,
556 int i_channels
, int *pi_chan_table
)
558 bool b_chan_reorder
= false;
561 if( i_channels
> AOUT_CHAN_MAX
)
564 if( pi_chan_order_in
== NULL
)
565 pi_chan_order_in
= pi_vlc_chan_order_wg4
;
566 if( pi_chan_order_out
== NULL
)
567 pi_chan_order_out
= pi_vlc_chan_order_wg4
;
569 for( i
= 0, j
= 0; pi_chan_order_in
[i
]; i
++ )
571 if( !(i_channel_mask
& pi_chan_order_in
[i
]) ) continue;
573 for( k
= 0, l
= 0; pi_chan_order_in
[i
] != pi_chan_order_out
[k
]; k
++ )
575 if( i_channel_mask
& pi_chan_order_out
[k
] ) l
++;
578 pi_chan_table
[j
++] = l
;
581 for( i
= 0; i
< i_channels
; i
++ )
583 if( pi_chan_table
[i
] != i
) b_chan_reorder
= true;
586 return b_chan_reorder
;
589 /*****************************************************************************
590 * aout_ChannelReorder :
591 *****************************************************************************/
592 void aout_ChannelReorder( uint8_t *p_buf
, int i_buffer
,
593 int i_channels
, const int *pi_chan_table
,
594 int i_bits_per_sample
)
596 uint8_t p_tmp
[AOUT_CHAN_MAX
* 4];
599 if( i_bits_per_sample
== 8 )
601 for( i
= 0; i
< i_buffer
/ i_channels
; i
++ )
603 for( j
= 0; j
< i_channels
; j
++ )
605 p_tmp
[pi_chan_table
[j
]] = p_buf
[j
];
608 memcpy( p_buf
, p_tmp
, i_channels
);
612 else if( i_bits_per_sample
== 16 )
614 for( i
= 0; i
< i_buffer
/ i_channels
/ 2; i
++ )
616 for( j
= 0; j
< i_channels
; j
++ )
618 p_tmp
[2 * pi_chan_table
[j
]] = p_buf
[2 * j
];
619 p_tmp
[2 * pi_chan_table
[j
] + 1] = p_buf
[2 * j
+ 1];
622 memcpy( p_buf
, p_tmp
, 2 * i_channels
);
623 p_buf
+= 2 * i_channels
;
626 else if( i_bits_per_sample
== 24 )
628 for( i
= 0; i
< i_buffer
/ i_channels
/ 3; i
++ )
630 for( j
= 0; j
< i_channels
; j
++ )
632 p_tmp
[3 * pi_chan_table
[j
]] = p_buf
[3 * j
];
633 p_tmp
[3 * pi_chan_table
[j
] + 1] = p_buf
[3 * j
+ 1];
634 p_tmp
[3 * pi_chan_table
[j
] + 2] = p_buf
[3 * j
+ 2];
637 memcpy( p_buf
, p_tmp
, 3 * i_channels
);
638 p_buf
+= 3 * i_channels
;
641 else if( i_bits_per_sample
== 32 )
643 for( i
= 0; i
< i_buffer
/ i_channels
/ 4; i
++ )
645 for( j
= 0; j
< i_channels
; j
++ )
647 p_tmp
[4 * pi_chan_table
[j
]] = p_buf
[4 * j
];
648 p_tmp
[4 * pi_chan_table
[j
] + 1] = p_buf
[4 * j
+ 1];
649 p_tmp
[4 * pi_chan_table
[j
] + 2] = p_buf
[4 * j
+ 2];
650 p_tmp
[4 * pi_chan_table
[j
] + 3] = p_buf
[4 * j
+ 3];
653 memcpy( p_buf
, p_tmp
, 4 * i_channels
);
654 p_buf
+= 4 * i_channels
;
659 /*****************************************************************************
660 * aout_ChannelExtract:
661 *****************************************************************************/
662 static inline void ExtractChannel( uint8_t *pi_dst
, int i_dst_channels
,
663 const uint8_t *pi_src
, int i_src_channels
,
665 const int *pi_selection
, int i_bytes
)
667 for( int i
= 0; i
< i_sample_count
; i
++ )
669 for( int j
= 0; j
< i_dst_channels
; j
++ )
670 memcpy( &pi_dst
[j
* i_bytes
], &pi_src
[pi_selection
[j
] * i_bytes
], i_bytes
);
671 pi_dst
+= i_dst_channels
* i_bytes
;
672 pi_src
+= i_src_channels
* i_bytes
;
676 void aout_ChannelExtract( void *p_dst
, int i_dst_channels
,
677 const void *p_src
, int i_src_channels
,
678 int i_sample_count
, const int *pi_selection
, int i_bits_per_sample
)
680 /* It does not work in place */
681 assert( p_dst
!= p_src
);
683 /* Force the compiler to inline for the specific cases so it can optimize */
684 if( i_bits_per_sample
== 8 )
685 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 1 );
686 else if( i_bits_per_sample
== 16 )
687 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 2 );
688 else if( i_bits_per_sample
== 24 )
689 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 3 );
690 else if( i_bits_per_sample
== 32 )
691 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 4 );
692 else if( i_bits_per_sample
== 64 )
693 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 8 );
696 bool aout_CheckChannelExtraction( int *pi_selection
,
697 uint32_t *pi_layout
, int *pi_channels
,
698 const uint32_t pi_order_dst
[AOUT_CHAN_MAX
],
699 const uint32_t *pi_order_src
, int i_channels
)
701 const uint32_t pi_order_dual_mono
[] = { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
};
702 uint32_t i_layout
= 0;
704 int pi_index
[AOUT_CHAN_MAX
];
708 pi_order_dst
= pi_vlc_chan_order_wg4
;
710 /* Detect special dual mono case */
711 if( i_channels
== 2 &&
712 pi_order_src
[0] == AOUT_CHAN_CENTER
&& pi_order_src
[1] == AOUT_CHAN_CENTER
)
714 i_layout
|= AOUT_CHAN_DUALMONO
;
715 pi_order_src
= pi_order_dual_mono
;
719 for( int i
= 0; i
< i_channels
; i
++ )
721 /* Ignore unknown or duplicated channels or not present in output */
722 if( !pi_order_src
[i
] || (i_layout
& pi_order_src
[i
]) )
725 for( int j
= 0; j
< AOUT_CHAN_MAX
; j
++ )
727 if( pi_order_dst
[j
] == pi_order_src
[i
] )
729 assert( i_out
< AOUT_CHAN_MAX
);
730 pi_index
[i_out
++] = i
;
731 i_layout
|= pi_order_src
[i
];
738 for( int i
= 0, j
= 0; i
< AOUT_CHAN_MAX
; i
++ )
740 for( int k
= 0; k
< i_out
; k
++ )
742 if( pi_order_dst
[i
] == pi_order_src
[pi_index
[k
]] )
744 pi_selection
[j
++] = pi_index
[k
];
750 *pi_layout
= i_layout
;
751 *pi_channels
= i_out
;
753 for( int i
= 0; i
< i_out
; i
++ )
755 if( pi_selection
[i
] != i
)
758 return i_out
== i_channels
;
761 /*****************************************************************************
763 *****************************************************************************/
765 aout_buffer_t
*aout_BufferAlloc(aout_alloc_t
*allocation
, mtime_t microseconds
,
766 aout_buffer_t
*old_buffer
)
768 if ( !allocation
->b_alloc
)
773 size_t i_alloc_size
= (int)( (uint64_t)allocation
->i_bytes_per_sec
774 * (microseconds
) / 1000000 + 1 );
776 return block_Alloc( i_alloc_size
);
779 /* Return the order in which filters should be inserted */
780 static int FilterOrder( const char *psz_name
)
782 static const struct {
783 const char *psz_name
;
789 for( int i
= 0; filter
[i
].psz_name
; i
++ )
791 if( !strcmp( filter
[i
].psz_name
, psz_name
) )
792 return filter
[i
].i_order
;
797 /* This function will add or remove a a module from a string list (colon
798 * separated). It will return true if there is a modification
799 * In case p_aout is NULL, we will use configuration instead of variable */
800 bool aout_ChangeFilterString( vlc_object_t
*p_obj
, aout_instance_t
*p_aout
,
801 const char *psz_variable
,
802 const char *psz_name
, bool b_add
)
804 if( *psz_name
== '\0' )
810 psz_list
= var_GetString( p_aout
, psz_variable
);
814 psz_list
= var_CreateGetString( p_obj
->p_libvlc
, psz_variable
);
815 var_Destroy( p_obj
->p_libvlc
, psz_variable
);
818 /* Split the string into an array of filters */
820 for( char *p
= psz_list
; p
&& *p
; p
++ )
821 i_count
+= *p
== ':';
824 const char **ppsz_filter
= calloc( i_count
, sizeof(*ppsz_filter
) );
830 bool b_present
= false;
832 for( char *p
= psz_list
; p
&& *p
; )
834 char *psz_end
= strchr(p
, ':');
838 psz_end
= p
+ strlen(p
);
841 b_present
|= !strcmp( p
, psz_name
);
842 ppsz_filter
[i_count
++] = p
;
846 if( b_present
== b_add
)
855 int i_order
= FilterOrder( psz_name
);
857 for( i
= 0; i
< i_count
; i
++ )
859 if( FilterOrder( ppsz_filter
[i
] ) > i_order
)
863 memmove( &ppsz_filter
[i
+1], &ppsz_filter
[i
], (i_count
- i
) * sizeof(*ppsz_filter
) );
864 ppsz_filter
[i
] = psz_name
;
869 for( int i
= 0; i
< i_count
; i
++ )
871 if( !strcmp( ppsz_filter
[i
], psz_name
) )
876 for( int i
= 0; i
< i_count
; i
++ )
877 i_length
+= 1 + strlen( ppsz_filter
[i
] );
879 char *psz_new
= malloc( i_length
+ 1 );
881 for( int i
= 0; i
< i_count
; i
++ )
883 if( *ppsz_filter
[i
] == '\0' )
886 strcat( psz_new
, ":" );
887 strcat( psz_new
, ppsz_filter
[i
] );
893 var_SetString( p_aout
, psz_variable
, psz_new
);
895 config_PutPsz( p_obj
, psz_variable
, psz_new
);