8627415805726071359fcbbd0148f9ca034b9e30
[vlc.git] / modules / arm_neon / simple_channel_mixer.c
1 /*****************************************************************************
2  * simple_channel_mixer.c : simple channel mixer plug-in using NEON assembly
3  *****************************************************************************
4  * Copyright (C) 2002, 2004, 2006-2009, 2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *          David Geldreich <david.geldreich@free.fr>
9  *          S├ębastien Toque
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_aout.h>
36 #include <vlc_filter.h>
37 #include <vlc_block.h>
38 #include <vlc_cpu.h>
39 #include <assert.h>
40
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 static int  OpenFilter( vlc_object_t * );
45
46 vlc_module_begin ()
47     set_description( N_("Audio filter for simple channel mixing using NEON assembly") )
48     set_category( CAT_AUDIO )
49     set_subcategory( SUBCAT_AUDIO_MISC )
50     set_capability( "audio converter", 20 )
51     set_callbacks( OpenFilter, NULL )
52 vlc_module_end ()
53
54 #define FILTER_WRAPPER(in, out)                                                  \
55     void convert_##in##to##out##_neon_asm(float *dst, const float *src, int num, bool lfeChannel); \
56     static block_t *Filter_##in##to##out (filter_t *p_filter, block_t *p_block)  \
57     {                                                                            \
58         block_t *p_out;                                                          \
59         if (!FilterInit( p_filter, p_block, &p_out ))                            \
60             return NULL;                                                         \
61         const float *p_src = (const float *)p_block->p_buffer;                   \
62         float *p_dest = (float *)p_out->p_buffer;                                \
63         convert_##in##to##out##_neon_asm( p_dest, p_src, p_block->i_nb_samples,  \
64                   p_filter->fmt_in.audio.i_physical_channels & AOUT_CHAN_LFE );  \
65         block_Release( p_block );                                                \
66         return p_out;                                                            \
67     }
68
69 #define TRY_FILTER(in, out)                                \
70     if ( b_input_##in && b_output_##out )                  \
71     {                                                      \
72         p_filter->pf_audio_filter = Filter_##in##to##out ; \
73         return VLC_SUCCESS;                                \
74     }
75
76 /*****************************************************************************
77  * Filter:
78  *****************************************************************************/
79 static bool FilterInit( filter_t *p_filter, block_t *p_block, block_t **pp_out )
80 {
81     if( !p_block || !p_block->i_nb_samples )
82     {
83         if( p_block )
84             block_Release( p_block );
85         return false;
86     }
87
88     size_t i_out_size = p_block->i_nb_samples *
89         p_filter->fmt_out.audio.i_bitspersample *
90         p_filter->fmt_out.audio.i_channels / 8;
91
92     block_t *p_out = block_Alloc( i_out_size );
93     if( !p_out )
94     {
95         msg_Warn( p_filter, "can't get output buffer" );
96         block_Release( p_block );
97         return false;
98     }
99
100     p_out->i_nb_samples = p_block->i_nb_samples;
101     p_out->i_dts = p_block->i_dts;
102     p_out->i_pts = p_block->i_pts;
103     p_out->i_length = p_block->i_length;
104
105     int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
106     int i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
107     p_out->i_buffer = p_block->i_buffer * i_output_nb / i_input_nb;
108
109     *pp_out = p_out;
110     return true;
111 }
112
113 FILTER_WRAPPER(7,2)
114 FILTER_WRAPPER(5,2)
115 FILTER_WRAPPER(4,2)
116 FILTER_WRAPPER(3,2)
117 FILTER_WRAPPER(7,1)
118 FILTER_WRAPPER(5,1)
119 FILTER_WRAPPER(7,4)
120 FILTER_WRAPPER(5,4)
121
122 /*****************************************************************************
123  * OpenFilter:
124  *****************************************************************************/
125 static int OpenFilter( vlc_object_t *p_this )
126 {
127     filter_t *p_filter = (filter_t *)p_this;
128
129     if (!vlc_CPU_ARM_NEON())
130         return VLC_EGENERIC;
131
132     audio_format_t fmt_in  = p_filter->fmt_in.audio;
133     audio_format_t fmt_out = p_filter->fmt_out.audio;
134
135     fmt_in.i_format = p_filter->fmt_in.i_codec;
136     fmt_out.i_format = p_filter->fmt_out.i_codec;
137
138     if( fmt_in.i_format != VLC_CODEC_FL32 ||
139         fmt_in.i_format != fmt_out.i_format ||
140         fmt_in.i_rate != fmt_out.i_rate )
141     {
142         return VLC_EGENERIC;
143     }
144
145     if( fmt_in.i_physical_channels == fmt_out.i_physical_channels &&
146         fmt_in.i_original_channels == fmt_out.i_original_channels )
147     {
148         return VLC_EGENERIC;
149     }
150
151     const bool b_input_7 = (fmt_in.i_physical_channels & ~AOUT_CHAN_LFE) == AOUT_CHANS_7_0;
152     const bool b_input_5 = ( (fmt_in.i_physical_channels & AOUT_CHANS_5_0) == AOUT_CHANS_5_0 ||
153                              (fmt_in.i_physical_channels & AOUT_CHANS_5_0_MIDDLE) == AOUT_CHANS_5_0_MIDDLE );
154     const bool b_input_4 =  (fmt_in.i_physical_channels & ~AOUT_CHAN_LFE) == AOUT_CHANS_4_CENTER_REAR;
155     const bool b_input_3 = (fmt_in.i_physical_channels & ~AOUT_CHAN_LFE) == AOUT_CHANS_3_0;
156
157     const bool b_output_1 = fmt_out.i_physical_channels == AOUT_CHAN_CENTER;
158     const bool b_output_2 = fmt_out.i_physical_channels == AOUT_CHANS_2_0;
159     const bool b_output_4 = fmt_out.i_physical_channels == AOUT_CHANS_4_0;
160
161     /* Only conversion to Mono, Stereo and 4.0 right now */
162     /* Only from 7/7.1/5/5.1/3/3.1/2.0
163      * XXX 5.X rear and middle are handled the same way */
164
165     TRY_FILTER(7,2)
166     TRY_FILTER(5,2)
167     TRY_FILTER(4,2)
168     TRY_FILTER(3,2)
169     TRY_FILTER(7,1)
170     TRY_FILTER(5,1)
171     TRY_FILTER(7,4)
172     TRY_FILTER(5,4)
173
174     return VLC_EGENERIC;
175 }