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 *****************************************************************************/
33 #include <vlc_common.h>
35 #include "aout_internal.h"
39 * Instances management (internal and external)
42 #define AOUT_ASSERT_FIFO_LOCKED aout_assert_fifo_locked(p_aout, p_fifo)
43 static inline void aout_assert_fifo_locked( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
49 if( p_fifo
== &p_aout
->output
.fifo
)
50 vlc_assert_locked( &p_aout
->output_fifo_lock
);
54 for( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
56 if( p_fifo
== &p_aout
->pp_inputs
[i
]->mixer
.fifo
)
58 vlc_assert_locked( &p_aout
->input_fifos_lock
);
62 if( i
== p_aout
->i_nb_inputs
)
63 vlc_assert_locked( &p_aout
->mixer_lock
);
72 static void aout_Destructor( vlc_object_t
* p_this
);
74 /*****************************************************************************
75 * aout_New: initialize aout structure
76 *****************************************************************************/
77 aout_instance_t
* __aout_New( vlc_object_t
* p_parent
)
79 aout_instance_t
* p_aout
;
81 /* Allocate descriptor. */
82 p_aout
= vlc_custom_create( p_parent
, sizeof( *p_aout
), VLC_OBJECT_AOUT
,
89 /* Initialize members. */
90 vlc_mutex_init( &p_aout
->input_fifos_lock
);
91 vlc_mutex_init( &p_aout
->mixer_lock
);
92 vlc_mutex_init( &p_aout
->volume_vars_lock
);
93 vlc_mutex_init( &p_aout
->output_fifo_lock
);
94 p_aout
->i_nb_inputs
= 0;
95 p_aout
->mixer_multiplier
= 1.0;
96 p_aout
->p_mixer
= NULL
;
97 p_aout
->output
.b_error
= 1;
98 p_aout
->output
.b_starving
= 1;
100 var_Create( p_aout
, "intf-change", VLC_VAR_BOOL
);
101 var_SetBool( p_aout
, "intf-change", true );
103 vlc_object_set_destructor( p_aout
, aout_Destructor
);
105 vlc_object_attach( p_aout
, p_parent
);
110 /*****************************************************************************
111 * aout_Destructor: destroy aout structure
112 *****************************************************************************/
113 static void aout_Destructor( vlc_object_t
* p_this
)
115 aout_instance_t
* p_aout
= (aout_instance_t
*)p_this
;
116 vlc_mutex_destroy( &p_aout
->input_fifos_lock
);
117 vlc_mutex_destroy( &p_aout
->mixer_lock
);
118 vlc_mutex_destroy( &p_aout
->volume_vars_lock
);
119 vlc_mutex_destroy( &p_aout
->output_fifo_lock
);
122 /* Lock ordering rules:
124 * Vars Mixer Input IFIFO OFIFO (< Inner lock)
125 * Vars No! Yes Yes Yes Yes
126 * Mixer No! No! Yes Yes Yes
127 * Input No! No! No! Yes Yes
128 * In FIFOs No! No! No! No! Yes
129 * Out FIFOs No! No! No! No! No!
134 static __thread
unsigned aout_locks
= 0;
136 void aout_lock (unsigned i
)
141 case VOLUME_VARS_LOCK
:
145 allowed
= VOLUME_VARS_LOCK
;
148 allowed
= VOLUME_VARS_LOCK
|MIXER_LOCK
;
150 case INPUT_FIFO_LOCK
:
151 allowed
= VOLUME_VARS_LOCK
|MIXER_LOCK
|INPUT_LOCK
;
153 case OUTPUT_FIFO_LOCK
:
154 allowed
= VOLUME_VARS_LOCK
|MIXER_LOCK
|INPUT_LOCK
|INPUT_FIFO_LOCK
;
160 if (aout_locks
& ~allowed
)
162 fprintf (stderr
, "Illegal audio lock transition (%x -> %x)\n",
163 aout_locks
, aout_locks
|i
);
170 void aout_unlock (unsigned i
)
172 assert (aout_locks
& i
);
178 * Formats management (internal and external)
181 /*****************************************************************************
182 * aout_FormatNbChannels : return the number of channels
183 *****************************************************************************/
184 unsigned int aout_FormatNbChannels( const audio_sample_format_t
* p_format
)
186 static const uint32_t pi_channels
[] =
187 { AOUT_CHAN_CENTER
, AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
,
188 AOUT_CHAN_REARCENTER
, AOUT_CHAN_REARLEFT
, AOUT_CHAN_REARRIGHT
,
189 AOUT_CHAN_MIDDLELEFT
, AOUT_CHAN_MIDDLERIGHT
, AOUT_CHAN_LFE
};
190 unsigned int i_nb
= 0, i
;
192 for ( i
= 0; i
< sizeof(pi_channels
)/sizeof(uint32_t); i
++ )
194 if ( p_format
->i_physical_channels
& pi_channels
[i
] ) i_nb
++;
200 /*****************************************************************************
201 * aout_BitsPerSample : get the number of bits per sample
202 *****************************************************************************/
203 unsigned int aout_BitsPerSample( vlc_fourcc_t i_format
)
205 switch( vlc_fourcc_GetCodec( AUDIO_ES
, i_format
) )
235 /* For these formats the caller has to indicate the parameters
241 /*****************************************************************************
242 * aout_FormatPrepare : compute the number of bytes per frame & frame length
243 *****************************************************************************/
244 void aout_FormatPrepare( audio_sample_format_t
* p_format
)
246 p_format
->i_channels
= aout_FormatNbChannels( p_format
);
247 p_format
->i_bitspersample
= aout_BitsPerSample( p_format
->i_format
);
248 if( p_format
->i_bitspersample
> 0 )
250 p_format
->i_bytes_per_frame
= ( p_format
->i_bitspersample
/ 8 )
251 * aout_FormatNbChannels( p_format
);
252 p_format
->i_frame_length
= 1;
256 /*****************************************************************************
257 * aout_FormatPrintChannels : print a channel in a human-readable form
258 *****************************************************************************/
259 const char * aout_FormatPrintChannels( const audio_sample_format_t
* p_format
)
261 switch ( p_format
->i_physical_channels
& AOUT_CHAN_PHYSMASK
)
264 case AOUT_CHAN_RIGHT
:
265 case AOUT_CHAN_CENTER
:
266 if ( (p_format
->i_original_channels
& AOUT_CHAN_CENTER
)
267 || (p_format
->i_original_channels
268 & (AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
)) )
270 else if ( p_format
->i_original_channels
& AOUT_CHAN_LEFT
)
273 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
:
274 if ( p_format
->i_original_channels
& AOUT_CHAN_REVERSESTEREO
)
276 if ( p_format
->i_original_channels
& AOUT_CHAN_DOLBYSTEREO
)
277 return "Dolby/Reverse";
278 return "Stereo/Reverse";
282 if ( p_format
->i_original_channels
& AOUT_CHAN_DOLBYSTEREO
)
284 else if ( p_format
->i_original_channels
& AOUT_CHAN_DUALMONO
)
286 else if ( p_format
->i_original_channels
== AOUT_CHAN_CENTER
)
287 return "Stereo/Mono";
288 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_RIGHT
) )
289 return "Stereo/Left";
290 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_LEFT
) )
291 return "Stereo/Right";
294 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
:
296 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_REARCENTER
:
298 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
299 | AOUT_CHAN_REARCENTER
:
301 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
302 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
:
304 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
305 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
:
307 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
308 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
:
310 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
311 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
:
314 case AOUT_CHAN_CENTER
| AOUT_CHAN_LFE
:
315 if ( (p_format
->i_original_channels
& AOUT_CHAN_CENTER
)
316 || (p_format
->i_original_channels
317 & (AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
)) )
319 else if ( p_format
->i_original_channels
& AOUT_CHAN_LEFT
)
322 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_LFE
:
323 if ( p_format
->i_original_channels
& AOUT_CHAN_DOLBYSTEREO
)
325 else if ( p_format
->i_original_channels
& AOUT_CHAN_DUALMONO
)
326 return "Dual-mono/LFE";
327 else if ( p_format
->i_original_channels
== AOUT_CHAN_CENTER
)
329 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_RIGHT
) )
330 return "Stereo/Left/LFE";
331 else if ( !(p_format
->i_original_channels
& AOUT_CHAN_LEFT
) )
332 return "Stereo/Right/LFE";
334 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
| AOUT_CHAN_LFE
:
336 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_REARCENTER
339 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
340 | AOUT_CHAN_REARCENTER
| AOUT_CHAN_LFE
:
342 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
343 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_LFE
:
345 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
346 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
| AOUT_CHAN_LFE
:
348 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
349 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_LFE
:
351 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
352 | AOUT_CHAN_MIDDLELEFT
| AOUT_CHAN_MIDDLERIGHT
| AOUT_CHAN_LFE
:
354 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
355 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_MIDDLELEFT
356 | AOUT_CHAN_MIDDLERIGHT
:
358 case AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
| AOUT_CHAN_CENTER
359 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
| AOUT_CHAN_MIDDLELEFT
360 | AOUT_CHAN_MIDDLERIGHT
| AOUT_CHAN_LFE
:
367 /*****************************************************************************
368 * aout_FormatPrint : print a format in a human-readable form
369 *****************************************************************************/
370 void aout_FormatPrint( aout_instance_t
* p_aout
, const char * psz_text
,
371 const audio_sample_format_t
* p_format
)
373 msg_Dbg( p_aout
, "%s '%4.4s' %d Hz %s frame=%d samples/%d bytes", psz_text
,
374 (char *)&p_format
->i_format
, p_format
->i_rate
,
375 aout_FormatPrintChannels( p_format
),
376 p_format
->i_frame_length
, p_format
->i_bytes_per_frame
);
379 /*****************************************************************************
380 * aout_FormatsPrint : print two formats in a human-readable form
381 *****************************************************************************/
382 void aout_FormatsPrint( aout_instance_t
* p_aout
, const char * psz_text
,
383 const audio_sample_format_t
* p_format1
,
384 const audio_sample_format_t
* p_format2
)
386 msg_Dbg( p_aout
, "%s '%4.4s'->'%4.4s' %d Hz->%d Hz %s->%s",
388 (char *)&p_format1
->i_format
, (char *)&p_format2
->i_format
,
389 p_format1
->i_rate
, p_format2
->i_rate
,
390 aout_FormatPrintChannels( p_format1
),
391 aout_FormatPrintChannels( p_format2
) );
396 * FIFO management (internal) - please understand that solving race conditions
397 * is _your_ job, ie. in the audio output you should own the mixer lock
398 * before calling any of these functions.
401 /*****************************************************************************
402 * aout_FifoInit : initialize the members of a FIFO
403 *****************************************************************************/
404 void aout_FifoInit( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
407 AOUT_ASSERT_FIFO_LOCKED
;
411 msg_Err( p_aout
, "initialising fifo with zero divider" );
414 p_fifo
->p_first
= NULL
;
415 p_fifo
->pp_last
= &p_fifo
->p_first
;
416 date_Init( &p_fifo
->end_date
, i_rate
, 1 );
419 /*****************************************************************************
420 * aout_FifoPush : push a packet into the FIFO
421 *****************************************************************************/
422 void aout_FifoPush( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
423 aout_buffer_t
* p_buffer
)
426 AOUT_ASSERT_FIFO_LOCKED
;
428 *p_fifo
->pp_last
= p_buffer
;
429 p_fifo
->pp_last
= &p_buffer
->p_next
;
430 *p_fifo
->pp_last
= NULL
;
431 /* Enforce the continuity of the stream. */
432 if ( date_Get( &p_fifo
->end_date
) )
434 p_buffer
->i_pts
= date_Get( &p_fifo
->end_date
);
435 p_buffer
->i_length
= date_Increment( &p_fifo
->end_date
,
436 p_buffer
->i_nb_samples
);
437 p_buffer
->i_length
-= p_buffer
->i_pts
;
441 date_Set( &p_fifo
->end_date
, p_buffer
->i_pts
+ p_buffer
->i_length
);
445 /*****************************************************************************
446 * aout_FifoSet : set end_date and trash all buffers (because they aren't
448 *****************************************************************************/
449 void aout_FifoSet( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
452 aout_buffer_t
* p_buffer
;
454 AOUT_ASSERT_FIFO_LOCKED
;
456 date_Set( &p_fifo
->end_date
, date
);
457 p_buffer
= p_fifo
->p_first
;
458 while ( p_buffer
!= NULL
)
460 aout_buffer_t
* p_next
= p_buffer
->p_next
;
461 aout_BufferFree( p_buffer
);
464 p_fifo
->p_first
= NULL
;
465 p_fifo
->pp_last
= &p_fifo
->p_first
;
468 /*****************************************************************************
469 * aout_FifoMoveDates : Move forwards or backwards all dates in the FIFO
470 *****************************************************************************/
471 void aout_FifoMoveDates( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
,
474 aout_buffer_t
* p_buffer
;
476 AOUT_ASSERT_FIFO_LOCKED
;
478 date_Move( &p_fifo
->end_date
, difference
);
479 p_buffer
= p_fifo
->p_first
;
480 while ( p_buffer
!= NULL
)
482 p_buffer
->i_pts
+= difference
;
483 p_buffer
= p_buffer
->p_next
;
487 /*****************************************************************************
488 * aout_FifoNextStart : return the current end_date
489 *****************************************************************************/
490 mtime_t
aout_FifoNextStart( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
493 AOUT_ASSERT_FIFO_LOCKED
;
494 return date_Get( &p_fifo
->end_date
);
497 /*****************************************************************************
498 * aout_FifoFirstDate : return the playing date of the first buffer in the
500 *****************************************************************************/
501 mtime_t
aout_FifoFirstDate( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
504 AOUT_ASSERT_FIFO_LOCKED
;
505 return p_fifo
->p_first
? p_fifo
->p_first
->i_pts
: 0;
508 /*****************************************************************************
509 * aout_FifoPop : get the next buffer out of the FIFO
510 *****************************************************************************/
511 aout_buffer_t
* aout_FifoPop( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
513 aout_buffer_t
* p_buffer
;
515 AOUT_ASSERT_FIFO_LOCKED
;
517 p_buffer
= p_fifo
->p_first
;
518 if ( p_buffer
== NULL
) return NULL
;
519 p_fifo
->p_first
= p_buffer
->p_next
;
520 if ( p_fifo
->p_first
== NULL
)
522 p_fifo
->pp_last
= &p_fifo
->p_first
;
528 /*****************************************************************************
529 * aout_FifoDestroy : destroy a FIFO and its buffers
530 *****************************************************************************/
531 void aout_FifoDestroy( aout_instance_t
* p_aout
, aout_fifo_t
* p_fifo
)
533 aout_buffer_t
* p_buffer
;
535 AOUT_ASSERT_FIFO_LOCKED
;
537 p_buffer
= p_fifo
->p_first
;
538 while ( p_buffer
!= NULL
)
540 aout_buffer_t
* p_next
= p_buffer
->p_next
;
541 aout_BufferFree( p_buffer
);
545 p_fifo
->p_first
= NULL
;
546 p_fifo
->pp_last
= &p_fifo
->p_first
;
549 /*****************************************************************************
550 * aout_CheckChannelReorder : Check if we need to do some channel re-ordering
551 *****************************************************************************/
552 int aout_CheckChannelReorder( const uint32_t *pi_chan_order_in
,
553 const uint32_t *pi_chan_order_out
,
554 uint32_t i_channel_mask
,
555 int i_channels
, int *pi_chan_table
)
557 bool b_chan_reorder
= false;
560 if( i_channels
> AOUT_CHAN_MAX
)
563 if( pi_chan_order_in
== NULL
)
564 pi_chan_order_in
= pi_vlc_chan_order_wg4
;
565 if( pi_chan_order_out
== NULL
)
566 pi_chan_order_out
= pi_vlc_chan_order_wg4
;
568 for( i
= 0, j
= 0; pi_chan_order_in
[i
]; i
++ )
570 if( !(i_channel_mask
& pi_chan_order_in
[i
]) ) continue;
572 for( k
= 0, l
= 0; pi_chan_order_in
[i
] != pi_chan_order_out
[k
]; k
++ )
574 if( i_channel_mask
& pi_chan_order_out
[k
] ) l
++;
577 pi_chan_table
[j
++] = l
;
580 for( i
= 0; i
< i_channels
; i
++ )
582 if( pi_chan_table
[i
] != i
) b_chan_reorder
= true;
585 return b_chan_reorder
;
588 /*****************************************************************************
589 * aout_ChannelReorder :
590 *****************************************************************************/
591 void aout_ChannelReorder( uint8_t *p_buf
, int i_buffer
,
592 int i_channels
, const int *pi_chan_table
,
593 int i_bits_per_sample
)
595 uint8_t p_tmp
[AOUT_CHAN_MAX
* 4];
598 if( i_bits_per_sample
== 8 )
600 for( i
= 0; i
< i_buffer
/ i_channels
; i
++ )
602 for( j
= 0; j
< i_channels
; j
++ )
604 p_tmp
[pi_chan_table
[j
]] = p_buf
[j
];
607 memcpy( p_buf
, p_tmp
, i_channels
);
611 else if( i_bits_per_sample
== 16 )
613 for( i
= 0; i
< i_buffer
/ i_channels
/ 2; i
++ )
615 for( j
= 0; j
< i_channels
; j
++ )
617 p_tmp
[2 * pi_chan_table
[j
]] = p_buf
[2 * j
];
618 p_tmp
[2 * pi_chan_table
[j
] + 1] = p_buf
[2 * j
+ 1];
621 memcpy( p_buf
, p_tmp
, 2 * i_channels
);
622 p_buf
+= 2 * i_channels
;
625 else if( i_bits_per_sample
== 24 )
627 for( i
= 0; i
< i_buffer
/ i_channels
/ 3; i
++ )
629 for( j
= 0; j
< i_channels
; j
++ )
631 p_tmp
[3 * pi_chan_table
[j
]] = p_buf
[3 * j
];
632 p_tmp
[3 * pi_chan_table
[j
] + 1] = p_buf
[3 * j
+ 1];
633 p_tmp
[3 * pi_chan_table
[j
] + 2] = p_buf
[3 * j
+ 2];
636 memcpy( p_buf
, p_tmp
, 3 * i_channels
);
637 p_buf
+= 3 * i_channels
;
640 else if( i_bits_per_sample
== 32 )
642 for( i
= 0; i
< i_buffer
/ i_channels
/ 4; i
++ )
644 for( j
= 0; j
< i_channels
; j
++ )
646 p_tmp
[4 * pi_chan_table
[j
]] = p_buf
[4 * j
];
647 p_tmp
[4 * pi_chan_table
[j
] + 1] = p_buf
[4 * j
+ 1];
648 p_tmp
[4 * pi_chan_table
[j
] + 2] = p_buf
[4 * j
+ 2];
649 p_tmp
[4 * pi_chan_table
[j
] + 3] = p_buf
[4 * j
+ 3];
652 memcpy( p_buf
, p_tmp
, 4 * i_channels
);
653 p_buf
+= 4 * i_channels
;
658 /*****************************************************************************
659 * aout_ChannelExtract:
660 *****************************************************************************/
661 static inline void ExtractChannel( uint8_t *pi_dst
, int i_dst_channels
,
662 const uint8_t *pi_src
, int i_src_channels
,
664 const int *pi_selection
, int i_bytes
)
666 for( int i
= 0; i
< i_sample_count
; i
++ )
668 for( int j
= 0; j
< i_dst_channels
; j
++ )
669 memcpy( &pi_dst
[j
* i_bytes
], &pi_src
[pi_selection
[j
] * i_bytes
], i_bytes
);
670 pi_dst
+= i_dst_channels
* i_bytes
;
671 pi_src
+= i_src_channels
* i_bytes
;
675 void aout_ChannelExtract( void *p_dst
, int i_dst_channels
,
676 const void *p_src
, int i_src_channels
,
677 int i_sample_count
, const int *pi_selection
, int i_bits_per_sample
)
679 /* It does not work in place */
680 assert( p_dst
!= p_src
);
682 /* Force the compiler to inline for the specific cases so it can optimize */
683 if( i_bits_per_sample
== 8 )
684 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 1 );
685 else if( i_bits_per_sample
== 16 )
686 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 2 );
687 else if( i_bits_per_sample
== 24 )
688 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 3 );
689 else if( i_bits_per_sample
== 32 )
690 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 4 );
691 else if( i_bits_per_sample
== 64 )
692 ExtractChannel( p_dst
, i_dst_channels
, p_src
, i_src_channels
, i_sample_count
, pi_selection
, 8 );
695 bool aout_CheckChannelExtraction( int *pi_selection
,
696 uint32_t *pi_layout
, int *pi_channels
,
697 const uint32_t pi_order_dst
[AOUT_CHAN_MAX
],
698 const uint32_t *pi_order_src
, int i_channels
)
700 const uint32_t pi_order_dual_mono
[] = { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
};
701 uint32_t i_layout
= 0;
703 int pi_index
[AOUT_CHAN_MAX
];
707 pi_order_dst
= pi_vlc_chan_order_wg4
;
709 /* Detect special dual mono case */
710 if( i_channels
== 2 &&
711 pi_order_src
[0] == AOUT_CHAN_CENTER
&& pi_order_src
[1] == AOUT_CHAN_CENTER
)
713 i_layout
|= AOUT_CHAN_DUALMONO
;
714 pi_order_src
= pi_order_dual_mono
;
718 for( int i
= 0; i
< i_channels
; i
++ )
720 /* Ignore unknown or duplicated channels or not present in output */
721 if( !pi_order_src
[i
] || (i_layout
& pi_order_src
[i
]) )
724 for( int j
= 0; j
< AOUT_CHAN_MAX
; j
++ )
726 if( pi_order_dst
[j
] == pi_order_src
[i
] )
728 assert( i_out
< AOUT_CHAN_MAX
);
729 pi_index
[i_out
++] = i
;
730 i_layout
|= pi_order_src
[i
];
737 for( int i
= 0, j
= 0; i
< AOUT_CHAN_MAX
; i
++ )
739 for( int k
= 0; k
< i_out
; k
++ )
741 if( pi_order_dst
[i
] == pi_order_src
[pi_index
[k
]] )
743 pi_selection
[j
++] = pi_index
[k
];
749 *pi_layout
= i_layout
;
750 *pi_channels
= i_out
;
752 for( int i
= 0; i
< i_out
; i
++ )
754 if( pi_selection
[i
] != i
)
757 return i_out
== i_channels
;
760 /*****************************************************************************
762 *****************************************************************************/
764 aout_buffer_t
*aout_BufferAlloc(aout_alloc_t
*allocation
, mtime_t microseconds
,
765 aout_buffer_t
*old_buffer
)
767 if ( !allocation
->b_alloc
)
772 size_t i_alloc_size
= (int)( (uint64_t)allocation
->i_bytes_per_sec
773 * (microseconds
) / 1000000 + 1 );
775 return block_Alloc( i_alloc_size
);