Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6148 | serge | 1 | /* |
2 | * audio conversion |
||
3 | * Copyright (c) 2006 Michael Niedermayer |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
7 | * FFmpeg is free software; you can redistribute it and/or |
||
8 | * modify it under the terms of the GNU Lesser General Public |
||
9 | * License as published by the Free Software Foundation; either |
||
10 | * version 2.1 of the License, or (at your option) any later version. |
||
11 | * |
||
12 | * FFmpeg is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
15 | * Lesser General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU Lesser General Public |
||
18 | * License along with FFmpeg; if not, write to the Free Software |
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
20 | */ |
||
21 | |||
22 | /** |
||
23 | * @file |
||
24 | * audio conversion |
||
25 | * @author Michael Niedermayer |
||
26 | */ |
||
27 | |||
28 | #include "libavutil/avstring.h" |
||
29 | #include "libavutil/avassert.h" |
||
30 | #include "libavutil/libm.h" |
||
31 | #include "libavutil/samplefmt.h" |
||
32 | #include "audioconvert.h" |
||
33 | |||
34 | |||
35 | #define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt |
||
36 | |||
37 | //FIXME rounding ? |
||
38 | #define CONV_FUNC(ofmt, otype, ifmt, expr)\ |
||
39 | static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end)\ |
||
40 | {\ |
||
41 | uint8_t *end2 = end - 3*os;\ |
||
42 | while(po < end2){\ |
||
43 | *(otype*)po = expr; pi += is; po += os;\ |
||
44 | *(otype*)po = expr; pi += is; po += os;\ |
||
45 | *(otype*)po = expr; pi += is; po += os;\ |
||
46 | *(otype*)po = expr; pi += is; po += os;\ |
||
47 | }\ |
||
48 | while(po < end){\ |
||
49 | *(otype*)po = expr; pi += is; po += os;\ |
||
50 | }\ |
||
51 | } |
||
52 | |||
53 | //FIXME put things below under ifdefs so we do not waste space for cases no codec will need |
||
54 | CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi) |
||
55 | CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8) |
||
56 | CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24) |
||
57 | CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0f/ (1<<7))) |
||
58 | CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) |
||
59 | CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80) |
||
60 | CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi) |
||
61 | CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16) |
||
62 | CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0f/ (1<<15))) |
||
63 | CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) |
||
64 | CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80) |
||
65 | CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16) |
||
66 | CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi) |
||
67 | CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0f/ (1U<<31))) |
||
68 | CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) |
||
69 | CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80)) |
||
70 | CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15)))) |
||
71 | CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31)))) |
||
72 | CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi) |
||
73 | CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi) |
||
74 | CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80)) |
||
75 | CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15)))) |
||
76 | CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31)))) |
||
77 | CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) |
||
78 | CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) |
||
79 | |||
80 | #define FMT_PAIR_FUNC(out, in) [out + AV_SAMPLE_FMT_NB*in] = CONV_FUNC_NAME(out, in) |
||
81 | |||
82 | static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAMPLE_FMT_NB] = { |
||
83 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_U8 ), |
||
84 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8 ), |
||
85 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8 ), |
||
86 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8 ), |
||
87 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8 ), |
||
88 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S16), |
||
89 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), |
||
90 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), |
||
91 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), |
||
92 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), |
||
93 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S32), |
||
94 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), |
||
95 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), |
||
96 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), |
||
97 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), |
||
98 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_FLT), |
||
99 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), |
||
100 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), |
||
101 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), |
||
102 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), |
||
103 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_DBL), |
||
104 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), |
||
105 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), |
||
106 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), |
||
107 | FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), |
||
108 | }; |
||
109 | |||
110 | static void cpy1(uint8_t **dst, const uint8_t **src, int len){ |
||
111 | memcpy(*dst, *src, len); |
||
112 | } |
||
113 | static void cpy2(uint8_t **dst, const uint8_t **src, int len){ |
||
114 | memcpy(*dst, *src, 2*len); |
||
115 | } |
||
116 | static void cpy4(uint8_t **dst, const uint8_t **src, int len){ |
||
117 | memcpy(*dst, *src, 4*len); |
||
118 | } |
||
119 | static void cpy8(uint8_t **dst, const uint8_t **src, int len){ |
||
120 | memcpy(*dst, *src, 8*len); |
||
121 | } |
||
122 | |||
123 | AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, |
||
124 | enum AVSampleFormat in_fmt, |
||
125 | int channels, const int *ch_map, |
||
126 | int flags) |
||
127 | { |
||
128 | AudioConvert *ctx; |
||
129 | conv_func_type *f = fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt) + AV_SAMPLE_FMT_NB*av_get_packed_sample_fmt(in_fmt)]; |
||
130 | |||
131 | if (!f) |
||
132 | return NULL; |
||
133 | ctx = av_mallocz(sizeof(*ctx)); |
||
134 | if (!ctx) |
||
135 | return NULL; |
||
136 | |||
137 | if(channels == 1){ |
||
138 | in_fmt = av_get_planar_sample_fmt( in_fmt); |
||
139 | out_fmt = av_get_planar_sample_fmt(out_fmt); |
||
140 | } |
||
141 | |||
142 | ctx->channels = channels; |
||
143 | ctx->conv_f = f; |
||
144 | ctx->ch_map = ch_map; |
||
145 | if (in_fmt == AV_SAMPLE_FMT_U8 || in_fmt == AV_SAMPLE_FMT_U8P) |
||
146 | memset(ctx->silence, 0x80, sizeof(ctx->silence)); |
||
147 | |||
148 | if(out_fmt == in_fmt && !ch_map) { |
||
149 | switch(av_get_bytes_per_sample(in_fmt)){ |
||
150 | case 1:ctx->simd_f = cpy1; break; |
||
151 | case 2:ctx->simd_f = cpy2; break; |
||
152 | case 4:ctx->simd_f = cpy4; break; |
||
153 | case 8:ctx->simd_f = cpy8; break; |
||
154 | } |
||
155 | } |
||
156 | |||
157 | if(HAVE_YASM && HAVE_MMX) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels); |
||
158 | if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels); |
||
159 | |||
160 | return ctx; |
||
161 | } |
||
162 | |||
163 | void swri_audio_convert_free(AudioConvert **ctx) |
||
164 | { |
||
165 | av_freep(ctx); |
||
166 | } |
||
167 | |||
168 | int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len) |
||
169 | { |
||
170 | int ch; |
||
171 | int off=0; |
||
172 | const int os= (out->planar ? 1 :out->ch_count) *out->bps; |
||
173 | unsigned misaligned = 0; |
||
174 | |||
175 | av_assert0(ctx->channels == out->ch_count); |
||
176 | |||
177 | if (ctx->in_simd_align_mask) { |
||
178 | int planes = in->planar ? in->ch_count : 1; |
||
179 | unsigned m = 0; |
||
180 | for (ch = 0; ch < planes; ch++) |
||
181 | m |= (intptr_t)in->ch[ch]; |
||
182 | misaligned |= m & ctx->in_simd_align_mask; |
||
183 | } |
||
184 | if (ctx->out_simd_align_mask) { |
||
185 | int planes = out->planar ? out->ch_count : 1; |
||
186 | unsigned m = 0; |
||
187 | for (ch = 0; ch < planes; ch++) |
||
188 | m |= (intptr_t)out->ch[ch]; |
||
189 | misaligned |= m & ctx->out_simd_align_mask; |
||
190 | } |
||
191 | |||
192 | //FIXME optimize common cases |
||
193 | |||
194 | if(ctx->simd_f && !ctx->ch_map && !misaligned){ |
||
195 | off = len&~15; |
||
196 | av_assert1(off>=0); |
||
197 | av_assert1(off<=len); |
||
198 | av_assert2(ctx->channels == SWR_CH_MAX || !in->ch[ctx->channels]); |
||
199 | if(off>0){ |
||
200 | if(out->planar == in->planar){ |
||
201 | int planes = out->planar ? out->ch_count : 1; |
||
202 | for(ch=0; ch |
||
203 | ctx->simd_f(out->ch+ch, (const uint8_t **)in->ch+ch, off * (out->planar ? 1 :out->ch_count)); |
||
204 | } |
||
205 | }else{ |
||
206 | ctx->simd_f(out->ch, (const uint8_t **)in->ch, off); |
||
207 | } |
||
208 | } |
||
209 | if(off == len) |
||
210 | return 0; |
||
211 | } |
||
212 | |||
213 | for(ch=0; ch |
||
214 | const int ich= ctx->ch_map ? ctx->ch_map[ch] : ch; |
||
215 | const int is= ich < 0 ? 0 : (in->planar ? 1 : in->ch_count) * in->bps; |
||
216 | const uint8_t *pi= ich < 0 ? ctx->silence : in->ch[ich]; |
||
217 | uint8_t *po= out->ch[ch]; |
||
218 | uint8_t *end= po + os*len; |
||
219 | if(!po) |
||
220 | continue; |
||
221 | ctx->conv_f(po+off*os, pi+off*is, is, os, end); |
||
222 | } |
||
223 | return 0; |
||
224 | }>>=len); |