+
+static const uint64_t pi_channels_map[][2] =
+{
+ { CH_FRONT_LEFT, AOUT_CHAN_LEFT },
+ { CH_FRONT_RIGHT, AOUT_CHAN_RIGHT },
+ { CH_FRONT_CENTER, AOUT_CHAN_CENTER },
+ { CH_LOW_FREQUENCY, AOUT_CHAN_LFE },
+ { CH_BACK_LEFT, AOUT_CHAN_REARLEFT },
+ { CH_BACK_RIGHT, AOUT_CHAN_REARRIGHT },
+ { CH_FRONT_LEFT_OF_CENTER, 0 },
+ { CH_FRONT_RIGHT_OF_CENTER, 0 },
+ { CH_BACK_CENTER, AOUT_CHAN_REARCENTER },
+ { CH_SIDE_LEFT, AOUT_CHAN_MIDDLELEFT },
+ { CH_SIDE_RIGHT, AOUT_CHAN_MIDDLERIGHT },
+ { CH_TOP_CENTER, 0 },
+ { CH_TOP_FRONT_LEFT, 0 },
+ { CH_TOP_FRONT_CENTER, 0 },
+ { CH_TOP_FRONT_RIGHT, 0 },
+ { CH_TOP_BACK_LEFT, 0 },
+ { CH_TOP_BACK_CENTER, 0 },
+ { CH_TOP_BACK_RIGHT, 0 },
+ { CH_STEREO_LEFT, 0 },
+ { CH_STEREO_RIGHT, 0 },
+};
+
+static void SetupOutputFormat( decoder_t *p_dec, bool b_trust )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ GetVlcAudioFormat( &p_dec->fmt_out.i_codec,
+ &p_dec->fmt_out.audio.i_bitspersample,
+ p_sys->p_context->sample_fmt );
+ p_dec->fmt_out.audio.i_rate = p_sys->p_context->sample_rate;
+
+ /* */
+ if( p_sys->i_previous_channels == p_sys->p_context->channels &&
+ p_sys->i_previous_layout == p_sys->p_context->channel_layout )
+ return;
+ if( b_trust )
+ {
+ p_sys->i_previous_channels = p_sys->p_context->channels;
+ p_sys->i_previous_layout = p_sys->p_context->channel_layout;
+ }
+
+ /* Specified order
+ * FIXME should we use fmt_in.audio.i_physical_channels or not ?
+ */
+ const unsigned i_order_max = 8 * sizeof(p_sys->p_context->channel_layout);
+ uint32_t pi_order_src[i_order_max];
+ int i_channels_src = 0;
+
+ if( p_sys->p_context->channel_layout )
+ {
+ for( unsigned i = 0; i < sizeof(pi_channels_map)/sizeof(*pi_channels_map); i++ )
+ {
+ if( p_sys->p_context->channel_layout & pi_channels_map[i][0] )
+ pi_order_src[i_channels_src++] = pi_channels_map[i][1];
+ }
+ }
+ else
+ {
+ /* Create default order */
+ if( b_trust )
+ msg_Warn( p_dec, "Physical channel configuration not set : guessing" );
+ for( unsigned int i = 0; i < __MIN( i_order_max, (unsigned)p_sys->p_context->channels ); i++ )
+ {
+ if( i < sizeof(pi_channels_map)/sizeof(*pi_channels_map) )
+ pi_order_src[i_channels_src++] = pi_channels_map[i][1];
+ }
+ }
+ if( i_channels_src != p_sys->p_context->channels && b_trust )
+ msg_Err( p_dec, "Channel layout not understood" );
+
+ uint32_t i_layout_dst;
+ int i_channels_dst;
+ p_sys->b_extract = aout_CheckChannelExtraction( p_sys->pi_extraction,
+ &i_layout_dst, &i_channels_dst,
+ NULL, pi_order_src, i_channels_src );
+ if( i_channels_dst != i_channels_src && b_trust )
+ msg_Warn( p_dec, "%d channels are dropped", i_channels_src - i_channels_dst );
+
+ p_dec->fmt_out.audio.i_physical_channels =
+ p_dec->fmt_out.audio.i_original_channels = i_layout_dst;
+ p_dec->fmt_out.audio.i_channels = i_channels_dst;
+}
+