31#include "libavcodec/avcodec.h"
32#include "libswresample/swresample.h"
36#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
37#include <QtProcessorDetection>
44#define LOC QString("AudioConvert: ")
48static inline bool sse2_check()
50#ifdef Q_PROCESSOR_X86_64
53 static int has_sse2 = -1;
55 return (
bool)has_sse2;
58#ifdef Q_PROCESSOR_X86_64
65 "and $0x4000000, %%edx \n\t"
67#ifdef Q_PROCESSOR_X86_64
75 return (
bool)has_sse2;
88static int toFloat8(
float* out,
const uint8_t* in,
int len)
91 float f = 1.0F / (1<<7);
94 if (sse2_check() && len >= 16)
101 "movd %3, %%xmm0 \n\t"
102 "movd %4, %%xmm7 \n\t"
103 "punpckldq %%xmm0, %%xmm0 \n\t"
104 "punpckldq %%xmm7, %%xmm7 \n\t"
105 "punpckldq %%xmm0, %%xmm0 \n\t"
106 "punpckldq %%xmm7, %%xmm7 \n\t"
108 "movdqu (%1), %%xmm1 \n\t"
109 "xorpd %%xmm2, %%xmm2 \n\t"
110 "xorpd %%xmm3, %%xmm3 \n\t"
111 "psubb %%xmm0, %%xmm1 \n\t"
112 "xorpd %%xmm4, %%xmm4 \n\t"
113 "punpcklbw %%xmm1, %%xmm2 \n\t"
114 "xorpd %%xmm5, %%xmm5 \n\t"
115 "punpckhbw %%xmm1, %%xmm3 \n\t"
116 "punpcklwd %%xmm2, %%xmm4 \n\t"
117 "xorpd %%xmm6, %%xmm6 \n\t"
118 "punpckhwd %%xmm2, %%xmm5 \n\t"
119 "psrad $24, %%xmm4 \n\t"
120 "punpcklwd %%xmm3, %%xmm6 \n\t"
121 "psrad $24, %%xmm5 \n\t"
122 "punpckhwd %%xmm3, %%xmm1 \n\t"
123 "psrad $24, %%xmm6 \n\t"
124 "cvtdq2ps %%xmm4, %%xmm4 \n\t"
125 "psrad $24, %%xmm1 \n\t"
126 "cvtdq2ps %%xmm5, %%xmm5 \n\t"
127 "mulps %%xmm7, %%xmm4 \n\t"
128 "cvtdq2ps %%xmm6, %%xmm6 \n\t"
129 "mulps %%xmm7, %%xmm5 \n\t"
130 "movups %%xmm4, (%0) \n\t"
131 "cvtdq2ps %%xmm1, %%xmm1 \n\t"
132 "mulps %%xmm7, %%xmm6 \n\t"
133 "movups %%xmm5, 16(%0) \n\t"
134 "mulps %%xmm7, %%xmm1 \n\t"
135 "movups %%xmm6, 32(%0) \n\t"
137 "movups %%xmm1, 48(%0) \n\t"
142 :
"c"(loops),
"r"(a),
"r"(f)
143 :
"xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7"
148 *out++ = (*in++ - 0x80) * f;
168#ifdef Q_PROCESSOR_X86
169 if (sse2_check() && len >= 16)
171 int loops = len >> 4;
176 "movd %3, %%xmm0 \n\t"
177 "movd %4, %%xmm7 \n\t"
178 "punpckldq %%xmm0, %%xmm0 \n\t"
179 "punpckldq %%xmm7, %%xmm7 \n\t"
180 "punpckldq %%xmm0, %%xmm0 \n\t"
181 "punpckldq %%xmm7, %%xmm7 \n\t"
183 "movups (%1), %%xmm1 \n\t"
184 "movups 16(%1), %%xmm2 \n\t"
185 "mulps %%xmm7, %%xmm1 \n\t"
186 "movups 32(%1), %%xmm3 \n\t"
187 "mulps %%xmm7, %%xmm2 \n\t"
188 "cvtps2dq %%xmm1, %%xmm1 \n\t"
189 "movups 48(%1), %%xmm4 \n\t"
190 "mulps %%xmm7, %%xmm3 \n\t"
191 "cvtps2dq %%xmm2, %%xmm2 \n\t"
192 "mulps %%xmm7, %%xmm4 \n\t"
193 "cvtps2dq %%xmm3, %%xmm3 \n\t"
194 "packssdw %%xmm2, %%xmm1 \n\t"
195 "cvtps2dq %%xmm4, %%xmm4 \n\t"
196 "packssdw %%xmm4, %%xmm3 \n\t"
198 "packsswb %%xmm3, %%xmm1 \n\t"
199 "paddb %%xmm0, %%xmm1 \n\t"
200 "movdqu %%xmm1, (%0) \n\t"
205 :
"c"(loops),
"r"(a),
"r"(f)
206 :
"xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm7"
211 *out++ =
clip_uint8(std::lrintf(*in++ * f) + 0x80);
215static int toFloat16(
float* out,
const short* in,
int len)
218 float f = 1.0F / (1<<15);
220#ifdef Q_PROCESSOR_X86
221 if (sse2_check() && len >= 16)
223 int loops = len >> 4;
227 "movd %3, %%xmm7 \n\t"
228 "punpckldq %%xmm7, %%xmm7 \n\t"
229 "punpckldq %%xmm7, %%xmm7 \n\t"
231 "xorpd %%xmm2, %%xmm2 \n\t"
232 "movdqu (%1), %%xmm1 \n\t"
233 "xorpd %%xmm3, %%xmm3 \n\t"
234 "punpcklwd %%xmm1, %%xmm2 \n\t"
235 "movdqu 16(%1), %%xmm4 \n\t"
236 "punpckhwd %%xmm1, %%xmm3 \n\t"
237 "psrad $16, %%xmm2 \n\t"
238 "punpcklwd %%xmm4, %%xmm5 \n\t"
239 "psrad $16, %%xmm3 \n\t"
240 "cvtdq2ps %%xmm2, %%xmm2 \n\t"
241 "punpckhwd %%xmm4, %%xmm6 \n\t"
242 "psrad $16, %%xmm5 \n\t"
243 "mulps %%xmm7, %%xmm2 \n\t"
244 "cvtdq2ps %%xmm3, %%xmm3 \n\t"
245 "psrad $16, %%xmm6 \n\t"
246 "mulps %%xmm7, %%xmm3 \n\t"
247 "cvtdq2ps %%xmm5, %%xmm5 \n\t"
248 "movups %%xmm2, (%0) \n\t"
249 "cvtdq2ps %%xmm6, %%xmm6 \n\t"
250 "mulps %%xmm7, %%xmm5 \n\t"
251 "movups %%xmm3, 16(%0) \n\t"
252 "mulps %%xmm7, %%xmm6 \n\t"
253 "movups %%xmm5, 32(%0) \n\t"
255 "movups %%xmm6, 48(%0) \n\t"
261 :
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7"
272 if ((a+0x8000) & ~0xFFFF)
273 return (a>>31) ^ 0x7FFF;
282#ifdef Q_PROCESSOR_X86
283 if (sse2_check() && len >= 16)
285 int loops = len >> 4;
289 "movd %3, %%xmm7 \n\t"
290 "punpckldq %%xmm7, %%xmm7 \n\t"
291 "punpckldq %%xmm7, %%xmm7 \n\t"
293 "movups (%1), %%xmm1 \n\t"
294 "movups 16(%1), %%xmm2 \n\t"
295 "mulps %%xmm7, %%xmm1 \n\t"
296 "movups 32(%1), %%xmm3 \n\t"
297 "mulps %%xmm7, %%xmm2 \n\t"
298 "cvtps2dq %%xmm1, %%xmm1 \n\t"
299 "movups 48(%1), %%xmm4 \n\t"
300 "mulps %%xmm7, %%xmm3 \n\t"
301 "cvtps2dq %%xmm2, %%xmm2 \n\t"
302 "mulps %%xmm7, %%xmm4 \n\t"
303 "cvtps2dq %%xmm3, %%xmm3 \n\t"
304 "cvtps2dq %%xmm4, %%xmm4 \n\t"
305 "packssdw %%xmm2, %%xmm1 \n\t"
306 "packssdw %%xmm4, %%xmm3 \n\t"
308 "movdqu %%xmm1, (%0) \n\t"
309 "movdqu %%xmm3, 16(%0) \n\t"
315 :
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm7"
328 float f = 1.0F / ((
uint)(1<<(bits-1)));
329 int shift = 32 - bits;
334#ifdef Q_PROCESSOR_X86
335 if (sse2_check() && len >= 16)
337 int loops = len >> 4;
341 "movd %3, %%xmm7 \n\t"
342 "punpckldq %%xmm7, %%xmm7 \n\t"
343 "movd %4, %%xmm6 \n\t"
344 "punpckldq %%xmm7, %%xmm7 \n\t"
346 "movdqu (%1), %%xmm1 \n\t"
347 "movdqu 16(%1), %%xmm2 \n\t"
348 "psrad %%xmm6, %%xmm1 \n\t"
349 "movdqu 32(%1), %%xmm3 \n\t"
350 "cvtdq2ps %%xmm1, %%xmm1 \n\t"
351 "psrad %%xmm6, %%xmm2 \n\t"
352 "movdqu 48(%1), %%xmm4 \n\t"
353 "cvtdq2ps %%xmm2, %%xmm2 \n\t"
354 "psrad %%xmm6, %%xmm3 \n\t"
355 "mulps %%xmm7, %%xmm1 \n\t"
356 "psrad %%xmm6, %%xmm4 \n\t"
357 "cvtdq2ps %%xmm3, %%xmm3 \n\t"
358 "movups %%xmm1, (%0) \n\t"
359 "mulps %%xmm7, %%xmm2 \n\t"
360 "cvtdq2ps %%xmm4, %%xmm4 \n\t"
361 "movups %%xmm2, 16(%0) \n\t"
362 "mulps %%xmm7, %%xmm3 \n\t"
363 "mulps %%xmm7, %%xmm4 \n\t"
364 "movups %%xmm3, 32(%0) \n\t"
366 "movups %%xmm4, 48(%0) \n\t"
371 :
"c"(loops),
"r"(f),
"r"(shift)
372 :
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm6",
"xmm7"
377 *out++ = (*in++ >> shift) * f;
385 float f = (
uint)(1<<(bits-1));
386 int shift = 32 - bits;
391#ifdef Q_PROCESSOR_X86
392 if (sse2_check() && len >= 16)
394 float o = 0.99999995;
396 int loops = len >> 4;
400 "movd %3, %%xmm7 \n\t"
401 "movss %4, %%xmm5 \n\t"
402 "punpckldq %%xmm7, %%xmm7 \n\t"
403 "movss %5, %%xmm6 \n\t"
404 "punpckldq %%xmm5, %%xmm5 \n\t"
405 "punpckldq %%xmm6, %%xmm6 \n\t"
406 "movd %6, %%xmm0 \n\t"
407 "punpckldq %%xmm7, %%xmm7 \n\t"
408 "punpckldq %%xmm5, %%xmm5 \n\t"
409 "punpckldq %%xmm6, %%xmm6 \n\t"
411 "movups (%1), %%xmm1 \n\t"
412 "movups 16(%1), %%xmm2 \n\t"
413 "minps %%xmm5, %%xmm1 \n\t"
414 "movups 32(%1), %%xmm3 \n\t"
415 "maxps %%xmm6, %%xmm1 \n\t"
416 "movups 48(%1), %%xmm4 \n\t"
417 "mulps %%xmm7, %%xmm1 \n\t"
418 "minps %%xmm5, %%xmm2 \n\t"
419 "cvtps2dq %%xmm1, %%xmm1 \n\t"
420 "maxps %%xmm6, %%xmm2 \n\t"
421 "pslld %%xmm0, %%xmm1 \n\t"
422 "minps %%xmm5, %%xmm3 \n\t"
423 "mulps %%xmm7, %%xmm2 \n\t"
424 "movdqu %%xmm1, (%0) \n\t"
425 "cvtps2dq %%xmm2, %%xmm2 \n\t"
426 "maxps %%xmm6, %%xmm3 \n\t"
427 "minps %%xmm5, %%xmm4 \n\t"
428 "pslld %%xmm0, %%xmm2 \n\t"
429 "mulps %%xmm7, %%xmm3 \n\t"
430 "maxps %%xmm6, %%xmm4 \n\t"
431 "movdqu %%xmm2, 16(%0) \n\t"
432 "cvtps2dq %%xmm3, %%xmm3 \n\t"
433 "mulps %%xmm7, %%xmm4 \n\t"
434 "pslld %%xmm0, %%xmm3 \n\t"
435 "cvtps2dq %%xmm4, %%xmm4 \n\t"
436 "movdqu %%xmm3, 32(%0) \n\t"
437 "pslld %%xmm0, %%xmm4 \n\t"
439 "movdqu %%xmm4, 48(%0) \n\t"
444 :
"c"(loops),
"r"(f),
"m"(o),
"m"(mo),
"r"(shift)
445 :
"xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7"
449 uint range = 1<<(bits-1);
456 *out++ = (range - 128) << shift;
461 *out++ = (-range) << shift;
464 *out++ = std::lrintf(valf * f) << shift;
473#ifdef Q_PROCESSOR_X86
474 if (sse2_check() && len >= 16)
476 int loops = len >> 4;
482 "movss %3, %%xmm6 \n\t"
483 "movss %4, %%xmm7 \n\t"
484 "punpckldq %%xmm6, %%xmm6 \n\t"
485 "punpckldq %%xmm7, %%xmm7 \n\t"
486 "punpckldq %%xmm6, %%xmm6 \n\t"
487 "punpckldq %%xmm7, %%xmm7 \n\t"
489 "movups (%1), %%xmm1 \n\t"
490 "movups 16(%1), %%xmm2 \n\t"
491 "minps %%xmm6, %%xmm1 \n\t"
492 "movups 32(%1), %%xmm3 \n\t"
493 "maxps %%xmm7, %%xmm1 \n\t"
494 "minps %%xmm6, %%xmm2 \n\t"
495 "movups 48(%1), %%xmm4 \n\t"
496 "maxps %%xmm7, %%xmm2 \n\t"
497 "movups %%xmm1, (%0) \n\t"
498 "minps %%xmm6, %%xmm3 \n\t"
499 "movups %%xmm2, 16(%0) \n\t"
500 "maxps %%xmm7, %%xmm3 \n\t"
501 "minps %%xmm6, %%xmm4 \n\t"
502 "movups %%xmm3, 32(%0) \n\t"
503 "maxps %%xmm7, %%xmm4 \n\t"
505 "movups %%xmm4, 48(%0) \n\t"
510 :
"c"(loops),
"m"(o),
"m"(mo)
511 :
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm6",
"xmm7"
542 memcpy(out, in,
bytes);
587 AVChannelLayout channel_layout;
588 av_channel_layout_default(&channel_layout, 1);
589 int ret = swr_alloc_set_opts2(&
m_swr,
597 if (!
m_swr || ret < 0)
600 LOG(VB_AUDIO, LOG_ERR,
LOC +
601 QString(
"error allocating resampler context (%1)")
606 ret = swr_init(
m_swr);
610 LOG(VB_AUDIO, LOG_ERR,
LOC +
611 QString(
"error initializing resampler context (%1)")
622 std::array<uint8_t*,1> outp {(uint8_t*)out};
623 std::array<const uint8_t*,1> inp {(
const uint8_t*)in};
625 int ret = swr_convert(
m_swr,
630 return ret * av_get_bytes_per_sample(
m_out);
666 memcpy(out, in,
bytes);
678 memcpy(out, in,
bytes);
695 alignas(16) std::array<uint8_t,65536> buffer {0};
704 s =
toFloat(
m_in, buffer.data(), in, buffer.size());
705 in =
static_cast<const uint8_t *
>(in) + s;
706 out =
static_cast<uint8_t *
>(out) +
fromFloat(
m_out, out, buffer.data(), s);
707 left -= buffer.size();
711 in =
static_cast<const uint8_t *
>(in) + s;
712 out =
static_cast<uint8_t *
>(out) +
fromFloat(
m_out, out, buffer.data(), s);
733 auto*
d = (
float*)dst;
734 auto* s = (
float*)src;
735 for (
int i = 0; i <
samples; i++)
742template <
class AudioDataType>
745 std::array<AudioDataType*,8> outp {};
747 for (
int i = 0; i < channels; i++)
749 outp[i] = out + (i * frames);
752 for (
int i = 0; i < frames; i++)
754 for (
int j = 0; j < channels; j++)
756 *(outp[j]++) = *(in++);
766 uint8_t*
output,
const uint8_t* input,
772 memcpy(
output, input, data_size);
791template <
class AudioDataType>
793 const AudioDataType*
const* inp =
nullptr)
795 std::array<const AudioDataType*,8> my_inp {};
800 memcpy(out, inp ? inp[0] : in,
sizeof(AudioDataType) * frames);
807 for (
int i = 0; i < channels; i++)
809 my_inp[i] = in + (i * frames);
814 for (
int i = 0; i < channels; i++)
820 for (
int i = 0; i < frames; i++)
822 for (
int j = 0; j < channels; j++)
824 *(out++) = *(my_inp[j]++);
835 uint8_t*
output,
const uint8_t*
const* input,
842 (
const char*
const*)input);
847 (
const short*
const*)input);
852 (
const int*
const*)input);
861 uint8_t*
output,
const uint8_t* input,
880 uint8_t*
output,
const uint8_t* input,
887 uint8_t*
output,
const uint8_t*
const* input,
894 uint8_t*
output,
const uint8_t* input,
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)
int Process(void *out, const void *in, int bytes) const
AudioConvertInternal(AVSampleFormat in, AVSampleFormat out)
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
AudioConvertInternal * m_ctx
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)
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
static const iso6937table * d
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static eu8 clamp(eu8 value, eu8 low, eu8 high)