qt: playlist: use item title if available
[vlc.git] / modules / audio_filter / channel_mixer / trivial.c
1 /*****************************************************************************
2  * trivial.c : trivial channel mixer plug-in (drops unwanted channels)
3  *****************************************************************************
4  * Copyright (C) 2002, 2006, 2014 VLC authors and VideoLAN
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_aout.h>
36 #include <vlc_filter.h>
37
38 static int Create( vlc_object_t * );
39
40 vlc_module_begin ()
41     set_description( N_("Audio filter for trivial channel mixing") )
42     set_capability( "audio converter", 1 )
43     set_category( CAT_AUDIO )
44     set_subcategory( SUBCAT_AUDIO_AFILTER )
45     set_callback( Create )
46 vlc_module_end ()
47
48 typedef struct
49 {
50     int channel_map[AOUT_CHAN_MAX];
51 } filter_sys_t;
52
53 /**
54  * Trivially upmixes
55  */
56 static block_t *Upmix( filter_t *p_filter, block_t *p_in_buf )
57 {
58     unsigned i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
59     unsigned i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
60
61     assert( i_input_nb < i_output_nb );
62
63     block_t *p_out_buf = block_Alloc(
64                               p_in_buf->i_buffer * i_output_nb / i_input_nb );
65     if( unlikely(p_out_buf == NULL) )
66     {
67         block_Release( p_in_buf );
68         return NULL;
69     }
70
71     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
72     p_out_buf->i_dts        = p_in_buf->i_dts;
73     p_out_buf->i_pts        = p_in_buf->i_pts;
74     p_out_buf->i_length     = p_in_buf->i_length;
75
76     filter_sys_t *p_sys = p_filter->p_sys;
77
78     float *p_dest = (float *)p_out_buf->p_buffer;
79     const float *p_src = (float *)p_in_buf->p_buffer;
80     const int *channel_map = p_sys->channel_map;
81
82     for( size_t i = 0; i < p_in_buf->i_nb_samples; i++ )
83     {
84         for( unsigned j = 0; j < i_output_nb; j++ )
85             p_dest[j] = channel_map[j] == -1 ? 0.f : p_src[channel_map[j]];
86
87         p_src += i_input_nb;
88         p_dest += i_output_nb;
89     }
90
91     block_Release( p_in_buf );
92     return p_out_buf;
93 }
94
95 /**
96  * Trivially downmixes (i.e. drop extra channels)
97  */
98 static block_t *Downmix( filter_t *p_filter, block_t *p_buf )
99 {
100     unsigned i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
101     unsigned i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
102
103     assert( i_input_nb >= i_output_nb );
104
105     filter_sys_t *p_sys = p_filter->p_sys;
106
107     float *p_dest = (float *)p_buf->p_buffer;
108     const float *p_src = p_dest;
109     const int *channel_map = p_sys->channel_map;
110     /* Use an extra buffer to avoid overlapping */
111     float buffer[i_output_nb];
112
113     for( size_t i = 0; i < p_buf->i_nb_samples; i++ )
114     {
115         for( unsigned j = 0; j < i_output_nb; j++ )
116             buffer[j] = channel_map[j] == -1 ? 0.f : p_src[channel_map[j]];
117         memcpy( p_dest, buffer, i_output_nb * sizeof(float) );
118
119         p_src += i_input_nb;
120         p_dest += i_output_nb;
121     }
122     p_buf->i_buffer = p_buf->i_buffer * i_output_nb / i_input_nb;
123
124     return p_buf;
125 }
126
127 static block_t *Equals( filter_t *p_filter, block_t *p_buf )
128 {
129     (void) p_filter;
130     return p_buf;
131 }
132
133 static block_t *Extract( filter_t *p_filter, block_t *p_in_buf )
134 {
135     size_t i_out_channels = aout_FormatNbChannels( &p_filter->fmt_out.audio );
136     size_t i_out_size = p_in_buf->i_nb_samples
137                       * p_filter->fmt_out.audio.i_bitspersample
138                       * i_out_channels / 8;
139
140     block_t *p_out_buf = block_Alloc( i_out_size );
141     if( unlikely(p_out_buf == NULL) )
142     {
143         block_Release( p_in_buf );
144         return NULL;
145     }
146
147     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
148     p_out_buf->i_dts        = p_in_buf->i_dts;
149     p_out_buf->i_pts        = p_in_buf->i_pts;
150     p_out_buf->i_length     = p_in_buf->i_length;
151
152     static const int pi_selections[] = {
153         0, 1, 2, 3, 4, 5, 6, 7, 8,
154     };
155     static_assert(sizeof(pi_selections)/sizeof(int) == AOUT_CHAN_MAX,
156                   "channel max size mismatch!");
157
158     aout_ChannelExtract( p_out_buf->p_buffer, i_out_channels,
159                          p_in_buf->p_buffer, p_filter->fmt_in.audio.i_channels,
160                          p_in_buf->i_nb_samples, pi_selections,
161                          p_filter->fmt_out.audio.i_bitspersample );
162
163     block_Release( p_in_buf );
164     return p_out_buf;
165 }
166
167 /**
168  * Probes the trivial channel mixer
169  */
170 static int Create( vlc_object_t *p_this )
171 {
172     filter_t *p_filter = (filter_t *)p_this;
173     const audio_format_t *infmt = &p_filter->fmt_in.audio;
174     const audio_format_t *outfmt = &p_filter->fmt_out.audio;
175
176     static const struct vlc_filter_operations equal_filter_ops =
177         { .filter_audio = Equals };
178
179     static const struct vlc_filter_operations extract_filter_ops =
180         { .filter_audio = Extract };
181
182     static const struct vlc_filter_operations upmix_filter_ops =
183         { .filter_audio = Upmix };
184
185     static const struct vlc_filter_operations downmix_filter_ops =
186         { .filter_audio = Downmix };
187
188     if( infmt->i_physical_channels == 0 )
189     {
190         assert( infmt->i_channels > 0 );
191         if( outfmt->i_physical_channels == 0 )
192             return VLC_EGENERIC;
193         if( aout_FormatNbChannels( outfmt ) == infmt->i_channels )
194         {
195             p_filter->ops = &equal_filter_ops;
196             return VLC_SUCCESS;
197         }
198         else
199         {
200             if( infmt->i_channels > AOUT_CHAN_MAX )
201                 msg_Info(p_filter, "%d channels will be dropped.",
202                          infmt->i_channels - AOUT_CHAN_MAX);
203             p_filter->ops = &extract_filter_ops;
204             return VLC_SUCCESS;
205         }
206     }
207
208     if( infmt->i_format != outfmt->i_format
209      || infmt->i_rate != outfmt->i_rate
210      || infmt->i_format != VLC_CODEC_FL32 )
211         return VLC_EGENERIC;
212
213     /* trivial is the lowest priority converter: if chan_mode are different
214      * here, this filter will still need to convert channels (and ignore
215      * chan_mode). */
216     if( infmt->i_physical_channels == outfmt->i_physical_channels
217      && infmt->i_chan_mode == outfmt->i_chan_mode )
218         return VLC_EGENERIC;
219
220     p_filter->p_sys = NULL;
221
222     if ( aout_FormatNbChannels( outfmt ) == 1
223       && aout_FormatNbChannels( infmt ) == 1 )
224     {
225         p_filter->ops = &equal_filter_ops;
226         return VLC_SUCCESS;
227     }
228
229     /* Setup channel order */
230     uint16_t i_in_physical_channels = infmt->i_physical_channels;
231     uint16_t i_out_physical_channels = outfmt->i_physical_channels;
232
233     /* Fill src_chans: contains a sorted index of all presents in channels */
234     int i_src_idx = 0;
235     int src_chans[AOUT_CHAN_MAX];
236     for( unsigned i = 0; i < AOUT_CHAN_MAX; ++i )
237         src_chans[i] = pi_vlc_chan_order_wg4[i] & i_in_physical_channels ?
238                        i_src_idx++ : -1;
239
240     unsigned i_dst_idx = 0;
241     int channel_map[AOUT_CHAN_MAX];
242     for( unsigned i = 0; i < AOUT_CHAN_MAX; ++i )
243     {
244         const uint32_t i_chan = pi_vlc_chan_order_wg4[i];
245         if( !( i_chan & i_out_physical_channels ) )
246             continue; /* Output channel not present */
247
248         if( aout_FormatNbChannels( infmt ) == 1 )
249         {
250             /* Input is mono, copy the mono channel to Left,Right */
251             if( i_chan & AOUT_CHANS_FRONT )
252                 channel_map[i_dst_idx] = 0;
253             else
254                 channel_map[i_dst_idx] = -1;
255         }
256         else if( src_chans[i] != -1 )
257         {
258             /* Input and output have the same channel */
259             assert( i_chan & i_in_physical_channels );
260             channel_map[i_dst_idx] = src_chans[i];
261         }
262         else
263         {
264             if( ( i_chan & AOUT_CHANS_MIDDLE )
265              && !( i_out_physical_channels & AOUT_CHANS_REAR ) )
266             {
267                 /* Use Rear chans as Middle chans if Rear chans are not used */
268                 assert( i + 2 < AOUT_CHAN_MAX );
269                 assert( pi_vlc_chan_order_wg4[i + 2] & AOUT_CHANS_REAR );
270                 channel_map[i_dst_idx] = src_chans[i + 2];
271             }
272             else if( ( i_chan & AOUT_CHANS_REAR )
273                   && !( i_out_physical_channels & AOUT_CHANS_MIDDLE ) )
274             {
275                 /* Use Middle chans as Rear chans if Middle chans are not used */
276                 assert( (int) i - 2 >= 0 );
277                 assert( pi_vlc_chan_order_wg4[i - 2] & AOUT_CHANS_MIDDLE );
278                 channel_map[i_dst_idx] = src_chans[i - 2];
279             }
280             else
281                 channel_map[i_dst_idx] = -1;
282         }
283         i_dst_idx++;
284     }
285 #ifndef NDEBUG
286     for( unsigned i = 0; i < aout_FormatNbChannels( outfmt ); ++i )
287     {
288         assert( channel_map[i] == -1
289              || (unsigned) channel_map[i] < aout_FormatNbChannels( infmt ) );
290     }
291 #endif
292
293     if( aout_FormatNbChannels( outfmt ) == aout_FormatNbChannels( infmt ) )
294     {
295         /* Channel layouts can be different but the channel order can be the
296          * same. This is the case for AOUT_CHANS_5_1 <-> AOUT_CHANS_5_1_MIDDLE
297          * for example. */
298         bool b_equals = true;
299         for( unsigned i = 0; i < aout_FormatNbChannels( outfmt ); ++i )
300             if( channel_map[i] == -1 || (unsigned) channel_map[i] != i )
301             {
302                 b_equals = false;
303                 break;
304             }
305         if( b_equals )
306         {
307             p_filter->ops = &equal_filter_ops;
308             return VLC_SUCCESS;
309         }
310     }
311
312     filter_sys_t *p_sys = vlc_obj_malloc( VLC_OBJECT(p_filter), sizeof(*p_sys) );
313     if( unlikely(!p_sys) )
314         return VLC_ENOMEM;
315     p_filter->p_sys = p_sys;
316     memcpy( p_sys->channel_map, channel_map, sizeof(channel_map) );
317
318     if( aout_FormatNbChannels( outfmt ) > aout_FormatNbChannels( infmt ) )
319         p_filter->ops = &upmix_filter_ops;
320     else
321         p_filter->ops = &downmix_filter_ops;
322
323     return VLC_SUCCESS;
324 }