1 /*****************************************************************************
2 * trivial.c : trivial channel mixer plug-in (drops unwanted channels)
3 *****************************************************************************
4 * Copyright (C) 2002, 2006, 2014 VLC authors and VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
38 static int Create( vlc_object_t
* );
39 static void Destroy( vlc_object_t
* );
42 set_description( N_("Audio filter for trivial channel mixing") )
43 set_capability( "audio converter", 1 )
44 set_category( CAT_AUDIO
)
45 set_subcategory( SUBCAT_AUDIO_MISC
)
46 set_callbacks( Create
, Destroy
)
51 int channel_map
[AOUT_CHAN_MAX
];
57 static block_t
*Upmix( filter_t
*p_filter
, block_t
*p_in_buf
)
59 unsigned i_input_nb
= aout_FormatNbChannels( &p_filter
->fmt_in
.audio
);
60 unsigned i_output_nb
= aout_FormatNbChannels( &p_filter
->fmt_out
.audio
);
62 assert( i_input_nb
< i_output_nb
);
64 block_t
*p_out_buf
= block_Alloc(
65 p_in_buf
->i_buffer
* i_output_nb
/ i_input_nb
);
66 if( unlikely(p_out_buf
== NULL
) )
68 block_Release( p_in_buf
);
72 p_out_buf
->i_nb_samples
= p_in_buf
->i_nb_samples
;
73 p_out_buf
->i_dts
= p_in_buf
->i_dts
;
74 p_out_buf
->i_pts
= p_in_buf
->i_pts
;
75 p_out_buf
->i_length
= p_in_buf
->i_length
;
77 float *p_dest
= (float *)p_out_buf
->p_buffer
;
78 const float *p_src
= (float *)p_in_buf
->p_buffer
;
79 const int *channel_map
= p_filter
->p_sys
->channel_map
;
81 for( size_t i
= 0; i
< p_in_buf
->i_nb_samples
; i
++ )
83 for( unsigned j
= 0; j
< i_output_nb
; j
++ )
84 p_dest
[j
] = channel_map
[j
] == -1 ? 0.f
: p_src
[channel_map
[j
]];
87 p_dest
+= i_output_nb
;
90 block_Release( p_in_buf
);
95 * Trivially downmixes (i.e. drop extra channels)
97 static block_t
*Downmix( filter_t
*p_filter
, block_t
*p_buf
)
99 unsigned i_input_nb
= aout_FormatNbChannels( &p_filter
->fmt_in
.audio
);
100 unsigned i_output_nb
= aout_FormatNbChannels( &p_filter
->fmt_out
.audio
);
102 assert( i_input_nb
>= i_output_nb
);
104 float *p_dest
= (float *)p_buf
->p_buffer
;
105 const float *p_src
= p_dest
;
106 const int *channel_map
= p_filter
->p_sys
->channel_map
;
107 /* Use an extra buffer to avoid overlapping */
108 float buffer
[i_output_nb
];
110 for( size_t i
= 0; i
< p_buf
->i_nb_samples
; i
++ )
112 for( unsigned j
= 0; j
< i_output_nb
; j
++ )
113 buffer
[j
] = channel_map
[j
] == -1 ? 0.f
: p_src
[channel_map
[j
]];
114 memcpy( p_dest
, buffer
, i_output_nb
* sizeof(float) );
117 p_dest
+= i_output_nb
;
119 p_buf
->i_buffer
= p_buf
->i_buffer
* i_output_nb
/ i_input_nb
;
124 static block_t
*Equals( filter_t
*p_filter
, block_t
*p_buf
)
130 static block_t
*Extract( filter_t
*p_filter
, block_t
*p_in_buf
)
132 size_t i_out_channels
= aout_FormatNbChannels( &p_filter
->fmt_out
.audio
);
133 size_t i_out_size
= p_in_buf
->i_nb_samples
134 * p_filter
->fmt_out
.audio
.i_bitspersample
135 * i_out_channels
/ 8;
137 block_t
*p_out_buf
= block_Alloc( i_out_size
);
138 if( unlikely(p_out_buf
== NULL
) )
140 block_Release( p_in_buf
);
144 p_out_buf
->i_nb_samples
= p_in_buf
->i_nb_samples
;
145 p_out_buf
->i_dts
= p_in_buf
->i_dts
;
146 p_out_buf
->i_pts
= p_in_buf
->i_pts
;
147 p_out_buf
->i_length
= p_in_buf
->i_length
;
149 static const int pi_selections
[] = {
150 0, 1, 2, 3, 4, 5, 6, 7, 8,
152 static_assert(sizeof(pi_selections
)/sizeof(int) == AOUT_CHAN_MAX
,
153 "channel max size mismatch!");
155 aout_ChannelExtract( p_out_buf
->p_buffer
, i_out_channels
,
156 p_in_buf
->p_buffer
, p_filter
->fmt_in
.audio
.i_channels
,
157 p_in_buf
->i_nb_samples
, pi_selections
,
158 p_filter
->fmt_out
.audio
.i_bitspersample
);
164 * Probes the trivial channel mixer
166 static int Create( vlc_object_t
*p_this
)
168 filter_t
*p_filter
= (filter_t
*)p_this
;
169 const audio_format_t
*infmt
= &p_filter
->fmt_in
.audio
;
170 const audio_format_t
*outfmt
= &p_filter
->fmt_out
.audio
;
172 if( infmt
->i_physical_channels
== 0 )
174 assert( infmt
->i_channels
> 0 );
175 if( outfmt
->i_physical_channels
== 0 )
177 if( aout_FormatNbChannels( outfmt
) == infmt
->i_channels
)
179 p_filter
->pf_audio_filter
= Equals
;
184 if( infmt
->i_channels
> AOUT_CHAN_MAX
)
185 msg_Info(p_filter
, "%d channels will be dropped.",
186 infmt
->i_channels
- AOUT_CHAN_MAX
);
187 p_filter
->pf_audio_filter
= Extract
;
192 if( infmt
->i_format
!= outfmt
->i_format
193 || infmt
->i_rate
!= outfmt
->i_rate
194 || infmt
->i_format
!= VLC_CODEC_FL32
)
197 /* trivial is the lowest priority converter: if chan_mode are different
198 * here, this filter will still need to convert channels (and ignore
200 if( infmt
->i_physical_channels
== outfmt
->i_physical_channels
201 && infmt
->i_chan_mode
== outfmt
->i_chan_mode
)
204 p_filter
->p_sys
= NULL
;
206 if ( aout_FormatNbChannels( outfmt
) == 1
207 && aout_FormatNbChannels( infmt
) == 1 )
209 p_filter
->pf_audio_filter
= Equals
;
213 /* Setup channel order */
214 uint16_t i_in_physical_channels
= infmt
->i_physical_channels
;
215 uint16_t i_out_physical_channels
= outfmt
->i_physical_channels
;
217 /* Fill src_chans: contains a sorted index of all presents in channels */
219 int src_chans
[AOUT_CHAN_MAX
];
220 for( unsigned i
= 0; i
< AOUT_CHAN_MAX
; ++i
)
221 src_chans
[i
] = pi_vlc_chan_order_wg4
[i
] & i_in_physical_channels
?
224 unsigned i_dst_idx
= 0;
225 int channel_map
[AOUT_CHAN_MAX
];
226 for( unsigned i
= 0; i
< AOUT_CHAN_MAX
; ++i
)
228 const uint32_t i_chan
= pi_vlc_chan_order_wg4
[i
];
229 if( !( i_chan
& i_out_physical_channels
) )
230 continue; /* Output channel not present */
232 if( aout_FormatNbChannels( infmt
) == 1 )
234 /* Input is mono, copy the mono channel to Left,Right */
235 if( i_chan
& AOUT_CHANS_FRONT
)
236 channel_map
[i_dst_idx
] = 0;
238 channel_map
[i_dst_idx
] = -1;
240 else if( src_chans
[i
] != -1 )
242 /* Input and output have the same channel */
243 assert( i_chan
& i_in_physical_channels
);
244 channel_map
[i_dst_idx
] = src_chans
[i
];
248 if( ( i_chan
& AOUT_CHANS_MIDDLE
)
249 && !( i_out_physical_channels
& AOUT_CHANS_REAR
) )
251 /* Use Rear chans as Middle chans if Rear chans are not used */
252 assert( i
+ 2 < AOUT_CHAN_MAX
);
253 assert( pi_vlc_chan_order_wg4
[i
+ 2] & AOUT_CHANS_REAR
);
254 channel_map
[i_dst_idx
] = src_chans
[i
+ 2];
256 else if( ( i_chan
& AOUT_CHANS_REAR
)
257 && !( i_out_physical_channels
& AOUT_CHANS_MIDDLE
) )
259 /* Use Middle chans as Rear chans if Middle chans are not used */
260 assert( (int) i
- 2 >= 0 );
261 assert( pi_vlc_chan_order_wg4
[i
- 2] & AOUT_CHANS_MIDDLE
);
262 channel_map
[i_dst_idx
] = src_chans
[i
- 2];
265 channel_map
[i_dst_idx
] = -1;
270 for( unsigned i
= 0; i
< aout_FormatNbChannels( outfmt
); ++i
)
272 assert( channel_map
[i
] == -1
273 || (unsigned) channel_map
[i
] < aout_FormatNbChannels( infmt
) );
277 if( aout_FormatNbChannels( outfmt
) == aout_FormatNbChannels( infmt
) )
279 /* Channel layouts can be different but the channel order can be the
280 * same. This is the case for AOUT_CHANS_5_1 <-> AOUT_CHANS_5_1_MIDDLE
282 bool b_equals
= true;
283 for( unsigned i
= 0; i
< aout_FormatNbChannels( outfmt
); ++i
)
284 if( channel_map
[i
] == -1 || (unsigned) channel_map
[i
] != i
)
291 p_filter
->pf_audio_filter
= Equals
;
296 p_filter
->p_sys
= malloc( sizeof(*p_filter
->p_sys
) );
297 if(! p_filter
->p_sys
)
299 memcpy( p_filter
->p_sys
->channel_map
, channel_map
, sizeof(channel_map
) );
301 if( aout_FormatNbChannels( outfmt
) > aout_FormatNbChannels( infmt
) )
302 p_filter
->pf_audio_filter
= Upmix
;
304 p_filter
->pf_audio_filter
= Downmix
;
309 static void Destroy( vlc_object_t
*p_this
)
311 filter_t
*p_filter
= (filter_t
*)p_this
;
312 free( p_filter
->p_sys
);