MythTV master
audioconvert.cpp
Go to the documentation of this file.
1
2/*
3 * Class AudioConvert
4 * Created by Jean-Yves Avenard on 10/06/13.
5 *
6 * Copyright (C) Bubblestuff Pty Ltd 2013
7 * Copyright (C) foobum@gmail.com 2010
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23#include "audioconvert.h"
24
25#include <algorithm>
26#include <cmath>
27#include <cstdint>
28
29// FFmpeg
30extern "C" {
31#include "libavcodec/avcodec.h"
32#include "libswresample/swresample.h"
33}
34
35#include <QtGlobal>
36
38
39#include "mythaverror.h"
40
41#define LOC QString("AudioConvert: ")
42
43#ifdef Q_PROCESSOR_X86
44// Check cpuid for SSE2 support on x86 / x86_64
45static inline bool sse2_check()
46{
47#ifdef Q_PROCESSOR_X86_64
48 return true;
49#endif
50 static int has_sse2 = -1;
51 if (has_sse2 != -1)
52 return (bool)has_sse2;
53 __asm__(
54 // -fPIC - we may not clobber ebx/rbx
55#ifdef Q_PROCESSOR_X86_64
56 "push %%rbx \n\t"
57#else
58 "push %%ebx \n\t"
59#endif
60 "mov $1, %%eax \n\t"
61 "cpuid \n\t"
62 "and $0x4000000, %%edx \n\t"
63 "shr $26, %%edx \n\t"
64#ifdef Q_PROCESSOR_X86_64
65 "pop %%rbx \n\t"
66#else
67 "pop %%ebx \n\t"
68#endif
69 :"=d"(has_sse2)
70 ::"%eax","%ecx"
71 );
72 return (bool)has_sse2;
73}
74#endif //Q_PROCESSOR_X86
75
76static inline float clipcheck(float f)
77{
78 return std::clamp(f, -1.0F, 1.0F);
79}
80
81/*
82 The SSE code processes 16 bytes at a time and leaves any remainder for the C
83 */
84
85static int toFloat8(float* out, const uint8_t* in, int len)
86{
87 int i = 0;
88 float f = 1.0F / ((1<<7));
89
90#ifdef Q_PROCESSOR_X86
91 if (sse2_check() && len >= 16)
92 {
93 int loops = len >> 4;
94 i = loops << 4;
95 int a = 0x80808080;
96
97 __asm__ volatile (
98 "movd %3, %%xmm0 \n\t"
99 "movd %4, %%xmm7 \n\t"
100 "punpckldq %%xmm0, %%xmm0 \n\t"
101 "punpckldq %%xmm7, %%xmm7 \n\t"
102 "punpckldq %%xmm0, %%xmm0 \n\t"
103 "punpckldq %%xmm7, %%xmm7 \n\t"
104 "1: \n\t"
105 "movdqu (%1), %%xmm1 \n\t"
106 "xorpd %%xmm2, %%xmm2 \n\t"
107 "xorpd %%xmm3, %%xmm3 \n\t"
108 "psubb %%xmm0, %%xmm1 \n\t"
109 "xorpd %%xmm4, %%xmm4 \n\t"
110 "punpcklbw %%xmm1, %%xmm2 \n\t"
111 "xorpd %%xmm5, %%xmm5 \n\t"
112 "punpckhbw %%xmm1, %%xmm3 \n\t"
113 "punpcklwd %%xmm2, %%xmm4 \n\t"
114 "xorpd %%xmm6, %%xmm6 \n\t"
115 "punpckhwd %%xmm2, %%xmm5 \n\t"
116 "psrad $24, %%xmm4 \n\t"
117 "punpcklwd %%xmm3, %%xmm6 \n\t"
118 "psrad $24, %%xmm5 \n\t"
119 "punpckhwd %%xmm3, %%xmm1 \n\t"
120 "psrad $24, %%xmm6 \n\t"
121 "cvtdq2ps %%xmm4, %%xmm4 \n\t"
122 "psrad $24, %%xmm1 \n\t"
123 "cvtdq2ps %%xmm5, %%xmm5 \n\t"
124 "mulps %%xmm7, %%xmm4 \n\t"
125 "cvtdq2ps %%xmm6, %%xmm6 \n\t"
126 "mulps %%xmm7, %%xmm5 \n\t"
127 "movups %%xmm4, (%0) \n\t"
128 "cvtdq2ps %%xmm1, %%xmm1 \n\t"
129 "mulps %%xmm7, %%xmm6 \n\t"
130 "movups %%xmm5, 16(%0) \n\t"
131 "mulps %%xmm7, %%xmm1 \n\t"
132 "movups %%xmm6, 32(%0) \n\t"
133 "add $16, %1 \n\t"
134 "movups %%xmm1, 48(%0) \n\t"
135 "add $64, %0 \n\t"
136 "sub $1, %%ecx \n\t"
137 "jnz 1b \n\t"
138 :"+r"(out),"+r"(in)
139 :"c"(loops), "r"(a), "r"(f)
140 :"xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7"
141 );
142 }
143#endif //Q_PROCESSOR_X86
144 for (; i < len; i++)
145 *out++ = (*in++ - 0x80) * f;
146 return len << 2;
147}
148
149/*
150 The SSE code processes 16 bytes at a time and leaves any remainder for the C
151 - there is no remainder in practice */
152
153static inline uint8_t clip_uint8(long a)
154{
155 if (a&(~0xFF))
156 return (-a)>>31;
157 return a;
158}
159
160static int fromFloat8(uint8_t* out, const float* in, int len)
161{
162 int i = 0;
163 float f = (1<<7);
164
165#ifdef Q_PROCESSOR_X86
166 if (sse2_check() && len >= 16)
167 {
168 int loops = len >> 4;
169 i = loops << 4;
170 int a = 0x80808080;
171
172 __asm__ volatile (
173 "movd %3, %%xmm0 \n\t"
174 "movd %4, %%xmm7 \n\t"
175 "punpckldq %%xmm0, %%xmm0 \n\t"
176 "punpckldq %%xmm7, %%xmm7 \n\t"
177 "punpckldq %%xmm0, %%xmm0 \n\t"
178 "punpckldq %%xmm7, %%xmm7 \n\t"
179 "1: \n\t"
180 "movups (%1), %%xmm1 \n\t"
181 "movups 16(%1), %%xmm2 \n\t"
182 "mulps %%xmm7, %%xmm1 \n\t"
183 "movups 32(%1), %%xmm3 \n\t"
184 "mulps %%xmm7, %%xmm2 \n\t"
185 "cvtps2dq %%xmm1, %%xmm1 \n\t"
186 "movups 48(%1), %%xmm4 \n\t"
187 "mulps %%xmm7, %%xmm3 \n\t"
188 "cvtps2dq %%xmm2, %%xmm2 \n\t"
189 "mulps %%xmm7, %%xmm4 \n\t"
190 "cvtps2dq %%xmm3, %%xmm3 \n\t"
191 "packssdw %%xmm2, %%xmm1 \n\t"
192 "cvtps2dq %%xmm4, %%xmm4 \n\t"
193 "packssdw %%xmm4, %%xmm3 \n\t"
194 "add $64, %1 \n\t"
195 "packsswb %%xmm3, %%xmm1 \n\t"
196 "paddb %%xmm0, %%xmm1 \n\t"
197 "movdqu %%xmm1, (%0) \n\t"
198 "add $16, %0 \n\t"
199 "sub $1, %%ecx \n\t"
200 "jnz 1b \n\t"
201 :"+r"(out),"+r"(in)
202 :"c"(loops), "r"(a), "r"(f)
203 :"xmm0","xmm1","xmm2","xmm3","xmm4","xmm7"
204 );
205 }
206#endif //Q_PROCESSOR_X86
207 for (;i < len; i++)
208 *out++ = clip_uint8(lrintf(*in++ * f) + 0x80);
209 return len;
210}
211
212static int toFloat16(float* out, const short* in, int len)
213{
214 int i = 0;
215 float f = 1.0F / ((1<<15));
216
217#ifdef Q_PROCESSOR_X86
218 if (sse2_check() && len >= 16)
219 {
220 int loops = len >> 4;
221 i = loops << 4;
222
223 __asm__ volatile (
224 "movd %3, %%xmm7 \n\t"
225 "punpckldq %%xmm7, %%xmm7 \n\t"
226 "punpckldq %%xmm7, %%xmm7 \n\t"
227 "1: \n\t"
228 "xorpd %%xmm2, %%xmm2 \n\t"
229 "movdqu (%1), %%xmm1 \n\t"
230 "xorpd %%xmm3, %%xmm3 \n\t"
231 "punpcklwd %%xmm1, %%xmm2 \n\t"
232 "movdqu 16(%1), %%xmm4 \n\t"
233 "punpckhwd %%xmm1, %%xmm3 \n\t"
234 "psrad $16, %%xmm2 \n\t"
235 "punpcklwd %%xmm4, %%xmm5 \n\t"
236 "psrad $16, %%xmm3 \n\t"
237 "cvtdq2ps %%xmm2, %%xmm2 \n\t"
238 "punpckhwd %%xmm4, %%xmm6 \n\t"
239 "psrad $16, %%xmm5 \n\t"
240 "mulps %%xmm7, %%xmm2 \n\t"
241 "cvtdq2ps %%xmm3, %%xmm3 \n\t"
242 "psrad $16, %%xmm6 \n\t"
243 "mulps %%xmm7, %%xmm3 \n\t"
244 "cvtdq2ps %%xmm5, %%xmm5 \n\t"
245 "movups %%xmm2, (%0) \n\t"
246 "cvtdq2ps %%xmm6, %%xmm6 \n\t"
247 "mulps %%xmm7, %%xmm5 \n\t"
248 "movups %%xmm3, 16(%0) \n\t"
249 "mulps %%xmm7, %%xmm6 \n\t"
250 "movups %%xmm5, 32(%0) \n\t"
251 "add $32, %1 \n\t"
252 "movups %%xmm6, 48(%0) \n\t"
253 "add $64, %0 \n\t"
254 "sub $1, %%ecx \n\t"
255 "jnz 1b \n\t"
256 :"+r"(out),"+r"(in)
257 :"c"(loops), "r"(f)
258 :"xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7"
259 );
260 }
261#endif //Q_PROCESSOR_X86
262 for (; i < len; i++)
263 *out++ = *in++ * f;
264 return len << 2;
265}
266
267static inline short clip_short(long a)
268{
269 if ((a+0x8000) & ~0xFFFF)
270 return (a>>31) ^ 0x7FFF;
271 return a;
272}
273
274static int fromFloat16(short* out, const float* in, int len)
275{
276 int i = 0;
277 float f = (1<<15);
278
279#ifdef Q_PROCESSOR_X86
280 if (sse2_check() && len >= 16)
281 {
282 int loops = len >> 4;
283 i = loops << 4;
284
285 __asm__ volatile (
286 "movd %3, %%xmm7 \n\t"
287 "punpckldq %%xmm7, %%xmm7 \n\t"
288 "punpckldq %%xmm7, %%xmm7 \n\t"
289 "1: \n\t"
290 "movups (%1), %%xmm1 \n\t"
291 "movups 16(%1), %%xmm2 \n\t"
292 "mulps %%xmm7, %%xmm1 \n\t"
293 "movups 32(%1), %%xmm3 \n\t"
294 "mulps %%xmm7, %%xmm2 \n\t"
295 "cvtps2dq %%xmm1, %%xmm1 \n\t"
296 "movups 48(%1), %%xmm4 \n\t"
297 "mulps %%xmm7, %%xmm3 \n\t"
298 "cvtps2dq %%xmm2, %%xmm2 \n\t"
299 "mulps %%xmm7, %%xmm4 \n\t"
300 "cvtps2dq %%xmm3, %%xmm3 \n\t"
301 "cvtps2dq %%xmm4, %%xmm4 \n\t"
302 "packssdw %%xmm2, %%xmm1 \n\t"
303 "packssdw %%xmm4, %%xmm3 \n\t"
304 "add $64, %1 \n\t"
305 "movdqu %%xmm1, (%0) \n\t"
306 "movdqu %%xmm3, 16(%0) \n\t"
307 "add $32, %0 \n\t"
308 "sub $1, %%ecx \n\t"
309 "jnz 1b \n\t"
310 :"+r"(out),"+r"(in)
311 :"c"(loops), "r"(f)
312 :"xmm1","xmm2","xmm3","xmm4","xmm7"
313 );
314 }
315#endif //Q_PROCESSOR_X86
316 for (;i < len;i++)
317 *out++ = clip_short(lrintf(*in++ * f));
318 return len << 1;
319}
320
321static int toFloat32(AudioFormat format, float* out, const int* in, int len)
322{
323 int i = 0;
324 int bits = AudioOutputSettings::FormatToBits(format);
325 float f = 1.0F / ((uint)(1<<(bits-1)));
326 int shift = 32 - bits;
327
328 if (format == FORMAT_S24LSB)
329 shift = 0;
330
331#ifdef Q_PROCESSOR_X86
332 if (sse2_check() && len >= 16)
333 {
334 int loops = len >> 4;
335 i = loops << 4;
336
337 __asm__ volatile (
338 "movd %3, %%xmm7 \n\t"
339 "punpckldq %%xmm7, %%xmm7 \n\t"
340 "movd %4, %%xmm6 \n\t"
341 "punpckldq %%xmm7, %%xmm7 \n\t"
342 "1: \n\t"
343 "movdqu (%1), %%xmm1 \n\t"
344 "movdqu 16(%1), %%xmm2 \n\t"
345 "psrad %%xmm6, %%xmm1 \n\t"
346 "movdqu 32(%1), %%xmm3 \n\t"
347 "cvtdq2ps %%xmm1, %%xmm1 \n\t"
348 "psrad %%xmm6, %%xmm2 \n\t"
349 "movdqu 48(%1), %%xmm4 \n\t"
350 "cvtdq2ps %%xmm2, %%xmm2 \n\t"
351 "psrad %%xmm6, %%xmm3 \n\t"
352 "mulps %%xmm7, %%xmm1 \n\t"
353 "psrad %%xmm6, %%xmm4 \n\t"
354 "cvtdq2ps %%xmm3, %%xmm3 \n\t"
355 "movups %%xmm1, (%0) \n\t"
356 "mulps %%xmm7, %%xmm2 \n\t"
357 "cvtdq2ps %%xmm4, %%xmm4 \n\t"
358 "movups %%xmm2, 16(%0) \n\t"
359 "mulps %%xmm7, %%xmm3 \n\t"
360 "mulps %%xmm7, %%xmm4 \n\t"
361 "movups %%xmm3, 32(%0) \n\t"
362 "add $64, %1 \n\t"
363 "movups %%xmm4, 48(%0) \n\t"
364 "add $64, %0 \n\t"
365 "sub $1, %%ecx \n\t"
366 "jnz 1b \n\t"
367 :"+r"(out),"+r"(in)
368 :"c"(loops), "r"(f), "r"(shift)
369 :"xmm1","xmm2","xmm3","xmm4","xmm6","xmm7"
370 );
371 }
372#endif //Q_PROCESSOR_X86
373 for (; i < len; i++)
374 *out++ = (*in++ >> shift) * f;
375 return len << 2;
376}
377
378static int fromFloat32(AudioFormat format, int* out, const float* in, int len)
379{
380 int i = 0;
381 int bits = AudioOutputSettings::FormatToBits(format);
382 float f = (uint)(1<<(bits-1));
383 int shift = 32 - bits;
384
385 if (format == FORMAT_S24LSB)
386 shift = 0;
387
388#ifdef Q_PROCESSOR_X86
389 if (sse2_check() && len >= 16)
390 {
391 float o = 0.99999995;
392 float mo = -1;
393 int loops = len >> 4;
394 i = loops << 4;
395
396 __asm__ volatile (
397 "movd %3, %%xmm7 \n\t"
398 "movss %4, %%xmm5 \n\t"
399 "punpckldq %%xmm7, %%xmm7 \n\t"
400 "movss %5, %%xmm6 \n\t"
401 "punpckldq %%xmm5, %%xmm5 \n\t"
402 "punpckldq %%xmm6, %%xmm6 \n\t"
403 "movd %6, %%xmm0 \n\t"
404 "punpckldq %%xmm7, %%xmm7 \n\t"
405 "punpckldq %%xmm5, %%xmm5 \n\t"
406 "punpckldq %%xmm6, %%xmm6 \n\t"
407 "1: \n\t"
408 "movups (%1), %%xmm1 \n\t"
409 "movups 16(%1), %%xmm2 \n\t"
410 "minps %%xmm5, %%xmm1 \n\t"
411 "movups 32(%1), %%xmm3 \n\t"
412 "maxps %%xmm6, %%xmm1 \n\t"
413 "movups 48(%1), %%xmm4 \n\t"
414 "mulps %%xmm7, %%xmm1 \n\t"
415 "minps %%xmm5, %%xmm2 \n\t"
416 "cvtps2dq %%xmm1, %%xmm1 \n\t"
417 "maxps %%xmm6, %%xmm2 \n\t"
418 "pslld %%xmm0, %%xmm1 \n\t"
419 "minps %%xmm5, %%xmm3 \n\t"
420 "mulps %%xmm7, %%xmm2 \n\t"
421 "movdqu %%xmm1, (%0) \n\t"
422 "cvtps2dq %%xmm2, %%xmm2 \n\t"
423 "maxps %%xmm6, %%xmm3 \n\t"
424 "minps %%xmm5, %%xmm4 \n\t"
425 "pslld %%xmm0, %%xmm2 \n\t"
426 "mulps %%xmm7, %%xmm3 \n\t"
427 "maxps %%xmm6, %%xmm4 \n\t"
428 "movdqu %%xmm2, 16(%0) \n\t"
429 "cvtps2dq %%xmm3, %%xmm3 \n\t"
430 "mulps %%xmm7, %%xmm4 \n\t"
431 "pslld %%xmm0, %%xmm3 \n\t"
432 "cvtps2dq %%xmm4, %%xmm4 \n\t"
433 "movdqu %%xmm3, 32(%0) \n\t"
434 "pslld %%xmm0, %%xmm4 \n\t"
435 "add $64, %1 \n\t"
436 "movdqu %%xmm4, 48(%0) \n\t"
437 "add $64, %0 \n\t"
438 "sub $1, %%ecx \n\t"
439 "jnz 1b \n\t"
440 :"+r"(out), "+r"(in)
441 :"c"(loops), "r"(f), "m"(o), "m"(mo), "r"(shift)
442 :"xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7"
443 );
444 }
445#endif //Q_PROCESSOR_X86
446 uint range = 1<<(bits-1);
447 for (; i < len; i++)
448 {
449 float valf = *in++;
450
451 if (valf >= 1.0F)
452 {
453 *out++ = (range - 128) << shift;
454 continue;
455 }
456 if (valf <= -1.0F)
457 {
458 *out++ = (-range) << shift;
459 continue;
460 }
461 *out++ = lrintf(valf * f) << shift;
462 }
463 return len << 2;
464}
465
466static int fromFloatFLT(float* out, const float* in, int len)
467{
468 int i = 0;
469
470#ifdef Q_PROCESSOR_X86
471 if (sse2_check() && len >= 16)
472 {
473 int loops = len >> 4;
474 float o = 1;
475 float mo = -1;
476 i = loops << 4;
477
478 __asm__ volatile (
479 "movss %3, %%xmm6 \n\t"
480 "movss %4, %%xmm7 \n\t"
481 "punpckldq %%xmm6, %%xmm6 \n\t"
482 "punpckldq %%xmm7, %%xmm7 \n\t"
483 "punpckldq %%xmm6, %%xmm6 \n\t"
484 "punpckldq %%xmm7, %%xmm7 \n\t"
485 "1: \n\t"
486 "movups (%1), %%xmm1 \n\t"
487 "movups 16(%1), %%xmm2 \n\t"
488 "minps %%xmm6, %%xmm1 \n\t"
489 "movups 32(%1), %%xmm3 \n\t"
490 "maxps %%xmm7, %%xmm1 \n\t"
491 "minps %%xmm6, %%xmm2 \n\t"
492 "movups 48(%1), %%xmm4 \n\t"
493 "maxps %%xmm7, %%xmm2 \n\t"
494 "movups %%xmm1, (%0) \n\t"
495 "minps %%xmm6, %%xmm3 \n\t"
496 "movups %%xmm2, 16(%0) \n\t"
497 "maxps %%xmm7, %%xmm3 \n\t"
498 "minps %%xmm6, %%xmm4 \n\t"
499 "movups %%xmm3, 32(%0) \n\t"
500 "maxps %%xmm7, %%xmm4 \n\t"
501 "add $64, %1 \n\t"
502 "movups %%xmm4, 48(%0) \n\t"
503 "add $64, %0 \n\t"
504 "sub $1, %%ecx \n\t"
505 "jnz 1b \n\t"
506 :"+r"(out), "+r"(in)
507 :"c"(loops), "m"(o), "m"(mo)
508 :"xmm1","xmm2","xmm3","xmm4","xmm6","xmm7"
509 );
510 }
511#endif //Q_PROCESSOR_X86
512 for (;i < len;i++)
513 *out++ = clipcheck(*in++);
514 return len << 2;
515}
516
522int AudioConvert::toFloat(AudioFormat format, void* out, const void* in,
523 int bytes)
524{
525 if (bytes <= 0)
526 return 0;
527
528 switch (format)
529 {
530 case FORMAT_U8:
531 return toFloat8((float*)out, (uint8_t*)in, bytes);
532 case FORMAT_S16:
533 return toFloat16((float*)out, (short*)in, bytes >> 1);
534 case FORMAT_S24:
535 case FORMAT_S24LSB:
536 case FORMAT_S32:
537 return toFloat32(format, (float*)out, (int*)in, bytes >> 2);
538 case FORMAT_FLT:
539 memcpy(out, in, bytes);
540 return bytes;
541 case FORMAT_NONE:
542 default:
543 return 0;
544 }
545}
546
552int AudioConvert::fromFloat(AudioFormat format, void* out, const void* in,
553 int bytes)
554{
555 if (bytes <= 0)
556 return 0;
557
558 switch (format)
559 {
560 case FORMAT_U8:
561 return fromFloat8((uint8_t*)out, (float*)in, bytes >> 2);
562 case FORMAT_S16:
563 return fromFloat16((short*)out, (float*)in, bytes >> 2);
564 case FORMAT_S24:
565 case FORMAT_S24LSB:
566 case FORMAT_S32:
567 return fromFloat32(format, (int*)out, (float*)in, bytes >> 2);
568 case FORMAT_FLT:
569 return fromFloatFLT((float*)out, (float*)in, bytes >> 2);
570 case FORMAT_NONE:
571 default:
572 return 0;
573 }
574}
575
577
579{
580public:
581 AudioConvertInternal(AVSampleFormat in, AVSampleFormat out) :
582 m_in(in), m_out(out)
583 {
584 AVChannelLayout channel_layout;
585 av_channel_layout_default(&channel_layout, 1);
586 int ret = swr_alloc_set_opts2(&m_swr,
587 &channel_layout,
588 m_out,
589 48000,
590 &channel_layout,
591 m_in,
592 48000,
593 0, nullptr);
594 if (!m_swr || ret < 0)
595 {
596 std::string error;
597 LOG(VB_AUDIO, LOG_ERR, LOC +
598 QString("error allocating resampler context (%1)")
599 .arg(av_make_error_stdstring(error, ret)));
600 return;
601 }
602 /* initialize the resampling context */
603 ret = swr_init(m_swr);
604 if (ret < 0)
605 {
606 std::string error;
607 LOG(VB_AUDIO, LOG_ERR, LOC +
608 QString("error initializing resampler context (%1)")
609 .arg(av_make_error_stdstring(error, ret)));
610 swr_free(&m_swr);
611 return;
612 }
613 }
614 int Process(void* out, const void* in, int bytes) const
615 {
616 if (!m_swr)
617 return -1;
618
619 std::array<uint8_t*,1> outp {(uint8_t*)out};
620 std::array<const uint8_t*,1> inp {(const uint8_t*)in};
621 int samples = bytes / av_get_bytes_per_sample(m_in);
622 int ret = swr_convert(m_swr,
623 outp.data(), samples,
624 inp.data(), samples);
625 if (ret < 0)
626 return ret;
627 return ret * av_get_bytes_per_sample(m_out);
628 }
630 {
631 if (m_swr)
632 {
633 swr_free(&m_swr);
634 }
635 }
636
637 SwrContext* m_swr {nullptr};
638 AVSampleFormat m_in, m_out;
639};
640
641
643{
644 delete m_ctx;
645 m_ctx = nullptr;
646}
647
654int AudioConvert::Process(void* out, const void* in, int bytes, bool noclip)
655{
656 if (bytes <= 0)
657 return 0;
658 if (m_out == FORMAT_NONE || m_in == FORMAT_NONE)
659 return 0;
660
661 if (noclip && m_in == m_out)
662 {
663 memcpy(out, in, bytes);
664 return bytes;
665 }
666
667 /* use conversion routines to perform clipping on samples */
668 if (m_in == FORMAT_FLT)
669 return fromFloat(m_out, out, in, bytes);
670 if (m_out == FORMAT_FLT)
671 return toFloat(m_in, out, in, bytes);
672
673 if (m_in == m_out)
674 {
675 memcpy(out, in, bytes);
676 return bytes;
677 }
678
679 if (m_in == FORMAT_S24 || m_in == FORMAT_S24LSB ||
681 {
682 // FFmpeg can't handle those, so use float conversion intermediary
684 {
685 // this can be done in place
686 int s = toFloat(m_in, out, in, bytes);
687 return fromFloat(m_out, out, out, s);
688 }
689 // this leave S24 -> U8/S16.
690 // TODO: native handling of those ; use internal temp buffer in the mean time
691
692 alignas(16) std::array<uint8_t,65536> buffer {0};
693 int left = bytes;
694
695 while (left > 0)
696 {
697 int s = 0;
698
699 if (left >= 65536)
700 {
701 s = toFloat(m_in, buffer.data(), in, buffer.size());
702 in = static_cast<const uint8_t *>(in) + s;
703 out = static_cast<uint8_t *>(out) + fromFloat(m_out, out, buffer.data(), s);
704 left -= buffer.size();
705 continue;
706 }
707 s = toFloat(m_in, buffer.data(), in, left);
708 in = static_cast<const uint8_t *>(in) + s;
709 out = static_cast<uint8_t *>(out) + fromFloat(m_out, out, buffer.data(), s);
710 left = 0;
711 }
713 }
714
715 // use FFmpeg conversion routine for S32<->S16, S32<->U8 and S16<->U8
716 if (!m_ctx)
717 {
720 }
721
722 return m_ctx->Process(out, in, bytes);
723}
724
728void AudioConvert::MonoToStereo(void* dst, const void* src, int samples)
729{
730 auto* d = (float*)dst;
731 auto* s = (float*)src;
732 for (int i = 0; i < samples; i++)
733 {
734 *d++ = *s;
735 *d++ = *s++;
736 }
737}
738
739template <class AudioDataType>
740void tDeinterleaveSample(AudioDataType* out, const AudioDataType* in, int channels, int frames)
741{
742 std::array<AudioDataType*,8> outp {};
743
744 for (int i = 0; i < channels; i++)
745 {
746 outp[i] = out + (i * frames);
747 }
748
749 for (int i = 0; i < frames; i++)
750 {
751 for (int j = 0; j < channels; j++)
752 {
753 *(outp[j]++) = *(in++);
754 }
755 }
756}
757
763 uint8_t* output, const uint8_t* input,
764 int data_size)
765{
766 if (channels == 1)
767 {
768 // If channel count is 1, planar and non-planar formats are the same
769 memcpy(output, input, data_size);
770 return;
771 }
772
773 int bits = AudioOutputSettings::FormatToBits(format);
774 if (bits == 8)
775 {
776 tDeinterleaveSample((char*)output, (const char*)input, channels, data_size/sizeof(char)/channels);
777 }
778 else if (bits == 16)
779 {
780 tDeinterleaveSample((short*)output, (const short*)input, channels, data_size/sizeof(short)/channels);
781 }
782 else
783 {
784 tDeinterleaveSample((int*)output, (const int*)input, channels, data_size/sizeof(int)/channels);
785 }
786}
787
788template <class AudioDataType>
789void tInterleaveSample(AudioDataType* out, const AudioDataType* in, int channels, int frames,
790 const AudioDataType* const* inp = nullptr)
791{
792 std::array<const AudioDataType*,8> my_inp {};
793
794 if (channels == 1)
795 {
796 //special case for mono
797 memcpy(out, inp ? inp[0] : in, sizeof(AudioDataType) * frames);
798 return;
799 }
800
801 if (!inp)
802 {
803 // We're given an array of int, calculate pointers to each row
804 for (int i = 0; i < channels; i++)
805 {
806 my_inp[i] = in + (i * frames);
807 }
808 }
809 else
810 {
811 for (int i = 0; i < channels; i++)
812 {
813 my_inp[i] = inp[i];
814 }
815 }
816
817 for (int i = 0; i < frames; i++)
818 {
819 for (int j = 0; j < channels; j++)
820 {
821 *(out++) = *(my_inp[j]++);
822 }
823 }
824}
825
832 uint8_t* output, const uint8_t* const* input,
833 int data_size)
834{
835 int bits = AudioOutputSettings::FormatToBits(format);
836 if (bits == 8)
837 {
838 tInterleaveSample((char*)output, (const char*)nullptr, channels, data_size/sizeof(char)/channels,
839 (const char* const*)input);
840 }
841 else if (bits == 16)
842 {
843 tInterleaveSample((short*)output, (const short*)nullptr, channels, data_size/sizeof(short)/channels,
844 (const short* const*)input);
845 }
846 else
847 {
848 tInterleaveSample((int*)output, (const int*)nullptr, channels, data_size/sizeof(int)/channels,
849 (const int* const*)input);
850 }
851}
852
858 uint8_t* output, const uint8_t* input,
859 int data_size)
860{
861 int bits = AudioOutputSettings::FormatToBits(format);
862 if (bits == 8)
863 {
864 tInterleaveSample((char*)output, (const char*)input, channels, data_size/sizeof(char)/channels);
865 }
866 else if (bits == 16)
867 {
868 tInterleaveSample((short*)output, (const short*)input, channels, data_size/sizeof(short)/channels);
869 }
870 else
871 {
872 tInterleaveSample((int*)output, (const int*)input, channels, data_size/sizeof(int)/channels);
873 }
874}
875
877 uint8_t* output, const uint8_t* input,
878 int data_size)
879{
880 DeinterleaveSamples(m_in, channels, output, input, data_size);
881}
882
884 uint8_t* output, const uint8_t* const* input,
885 int data_size)
886{
887 InterleaveSamples(m_in, channels, output, input, data_size);
888}
889
891 uint8_t* output, const uint8_t* input,
892 int data_size)
893{
894 InterleaveSamples(m_in, channels, output, input, data_size);
895}
#define LOC
void tDeinterleaveSample(AudioDataType *out, const AudioDataType *in, int channels, int frames)
static int fromFloatFLT(float *out, const float *in, int len)
static uint8_t clip_uint8(long a)
static float clipcheck(float f)
static int toFloat8(float *out, const uint8_t *in, int len)
static int fromFloat16(short *out, const float *in, int len)
static int fromFloat32(AudioFormat format, int *out, const float *in, int len)
static int toFloat16(float *out, const short *in, int len)
static int toFloat32(AudioFormat format, float *out, const int *in, int len)
void tInterleaveSample(AudioDataType *out, const AudioDataType *in, int channels, int frames, const AudioDataType *const *inp=nullptr)
static short clip_short(long a)
static int fromFloat8(uint8_t *out, const float *in, int len)
@ FORMAT_U8
@ FORMAT_S32
@ FORMAT_S24
@ FORMAT_NONE
@ FORMAT_FLT
@ FORMAT_S16
@ FORMAT_S24LSB
AVSampleFormat m_out
int Process(void *out, const void *in, int bytes) const
AVSampleFormat m_in
AudioConvertInternal(AVSampleFormat in, AVSampleFormat out)
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
virtual ~AudioConvert()
AudioConvertInternal * m_ctx
Definition: audioconvert.h:81
void DeinterleaveSamples(int channels, uint8_t *output, const uint8_t *input, int data_size)
static void MonoToStereo(void *dst, const void *src, int samples)
Convert a mono stream to stereo by copying and interleaving samples.
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
void InterleaveSamples(int channels, uint8_t *output, const uint8_t *const *input, int data_size)
AudioFormat m_in
Definition: audioconvert.h:82
AudioFormat m_out
Definition: audioconvert.h:82
int Process(void *out, const void *in, int bytes, bool noclip=false)
Process Parameters: out : destination buffer where converted samples will be copied in : source buffe...
static int SampleSize(AudioFormat format)
static AVSampleFormat FormatToAVSampleFormat(AudioFormat format)
Return AudioFormat closest equivalent to AVSampleFormat Note that FORMAT_S24LSB and FORMAT_S24 have n...
static int FormatToBits(AudioFormat format)
static const std::array< const uint64_t, 4 > samples
Definition: element.cpp:46
unsigned int uint
Definition: freesurround.h:24
static const iso6937table * d
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
Definition: mythaverror.cpp:42
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def error(message)
Definition: smolt.py:409
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206
#define output