MythTV  master
audiooutpututil.cpp
Go to the documentation of this file.
1 #include "audiooutpututil.h"
2 
3 #include <cstdint>
4 #include <limits> // workaround QTBUG-90395
5 
6 #include <QtGlobal>
7 #include <QtEndian>
8 
10 
11 #include "audioconvert.h"
12 #include "mythaverror.h"
13 
14 extern "C" {
15 #include "libavcodec/avcodec.h"
16 }
17 #include "pink.h"
18 
19 #define LOC QString("AOUtil: ")
20 
21 #ifdef Q_PROCESSOR_X86
22 // Check cpuid for SSE2 support on x86 / x86_64
23 static inline bool sse2_check()
24 {
25 #ifdef Q_PROCESSOR_X86_64
26  return true;
27 #endif
28  static int has_sse2 = -1;
29  if (has_sse2 != -1)
30  return (bool)has_sse2;
31  __asm__(
32  // -fPIC - we may not clobber ebx/rbx
33 #ifdef Q_PROCESSOR_X86_64
34  "push %%rbx \n\t"
35 #else
36  "push %%ebx \n\t"
37 #endif
38  "mov $1, %%eax \n\t"
39  "cpuid \n\t"
40  "and $0x4000000, %%edx \n\t"
41  "shr $26, %%edx \n\t"
42 #ifdef Q_PROCESSOR_X86_64
43  "pop %%rbx \n\t"
44 #else
45  "pop %%ebx \n\t"
46 #endif
47  :"=d"(has_sse2)
48  ::"%eax","%ecx"
49  );
50  return (bool)has_sse2;
51 }
52 #endif //Q_PROCESSOR_X86
53 
59 {
60 #ifdef Q_PROCESSOR_X86
61  return sse2_check();
62 #else
63  return false;
64 #endif
65 }
66 
72 int AudioOutputUtil::toFloat(AudioFormat format, void *out, const void *in,
73  int bytes)
74 {
75  return AudioConvert::toFloat(format, out, in, bytes);
76 }
77 
83 int AudioOutputUtil::fromFloat(AudioFormat format, void *out, const void *in,
84  int bytes)
85 {
86  return AudioConvert::fromFloat(format, out, in, bytes);
87 }
88 
92 void AudioOutputUtil::MonoToStereo(void *dst, const void *src, int samples)
93 {
95 }
96 
103 void AudioOutputUtil::AdjustVolume(void *buf, int len, int volume,
104  bool music, bool upmix)
105 {
106  float g = volume / 100.0F;
107  auto *fptr = (float *)buf;
108  int samples = len >> 2;
109  int i = 0;
110 
111  // Should be exponential - this'll do
112  g *= g;
113 
114  // Try to ~ match stereo volume when upmixing
115  if (upmix)
116  g *= 1.5F;
117 
118  // Music is relatively loud
119  if (music)
120  g *= 0.4F;
121 
122  if (g == 1.0F)
123  return;
124 
125 #ifdef Q_PROCESSOR_X86
126  if (sse2_check() && samples >= 16)
127  {
128  int loops = samples >> 4;
129  i = loops << 4;
130 
131  __asm__ volatile (
132  "movss %2, %%xmm0 \n\t"
133  "punpckldq %%xmm0, %%xmm0 \n\t"
134  "punpckldq %%xmm0, %%xmm0 \n\t"
135  "1: \n\t"
136  "movups (%0), %%xmm1 \n\t"
137  "movups 16(%0), %%xmm2 \n\t"
138  "mulps %%xmm0, %%xmm1 \n\t"
139  "movups 32(%0), %%xmm3 \n\t"
140  "mulps %%xmm0, %%xmm2 \n\t"
141  "movups 48(%0), %%xmm4 \n\t"
142  "mulps %%xmm0, %%xmm3 \n\t"
143  "movups %%xmm1, (%0) \n\t"
144  "mulps %%xmm0, %%xmm4 \n\t"
145  "movups %%xmm2, 16(%0) \n\t"
146  "movups %%xmm3, 32(%0) \n\t"
147  "movups %%xmm4, 48(%0) \n\t"
148  "add $64, %0 \n\t"
149  "sub $1, %%ecx \n\t"
150  "jnz 1b \n\t"
151  :"+r"(fptr)
152  :"c"(loops),"m"(g)
153  :"xmm0","xmm1","xmm2","xmm3","xmm4"
154  );
155  }
156 #endif //Q_PROCESSOR_X86
157  for (; i < samples; i++)
158  *fptr++ *= g;
159 }
160 
161 template <class AudioDataType>
162 void tMuteChannel(AudioDataType *buffer, int channels, int ch, int frames)
163 {
164  AudioDataType *s1 = buffer + ch;
165  AudioDataType *s2 = buffer - ch + 1;
166 
167  for (int i = 0; i < frames; i++)
168  {
169  *s1 = *s2;
170  s1 += channels;
171  s2 += channels;
172  }
173 }
174 
181 void AudioOutputUtil::MuteChannel(int obits, int channels, int ch,
182  void *buffer, int bytes)
183 {
184  int frames = bytes / ((obits >> 3) * channels);
185 
186  if (obits == 8)
187  tMuteChannel((uint8_t *)buffer, channels, ch, frames);
188  else if (obits == 16)
189  tMuteChannel((short *)buffer, channels, ch, frames);
190  else
191  tMuteChannel((int *)buffer, channels, ch, frames);
192 }
193 
194 char *AudioOutputUtil::GeneratePinkFrames(char *frames, int channels,
195  int channel, int count, int bits)
196 {
197  pink_noise_t pink{};
198 
199  initialize_pink_noise(&pink);
200 
201  auto *samp16 = (int16_t*) frames;
202  auto *samp32 = (int32_t*) frames;
203 
204  while (count-- > 0)
205  {
206  for(int chn = 0 ; chn < channels; chn++)
207  {
208  if (chn==channel)
209  {
210  /* Don't use MAX volume */
211  double res = generate_pink_noise_sample(&pink) *
212  static_cast<float>(0x03fffffff);
213  int32_t ires = res;
214  if (bits == 16)
215  *samp16++ = qToLittleEndian<qint16>(ires >> 16);
216  else
217  *samp32++ = qToLittleEndian<qint32>(ires);
218  }
219  else
220  {
221  if (bits == 16)
222  *samp16++ = 0;
223  else
224  *samp32++ = 0;
225  }
226  }
227  }
228  return frames;
229 }
230 
238 int AudioOutputUtil::DecodeAudio(AVCodecContext *ctx,
239  uint8_t *buffer, int &data_size,
240  const AVPacket *pkt)
241 {
242  MythAVFrame frame;
243  bool got_frame = false;
244 
245  data_size = 0;
246  if (!frame)
247  {
248  return AVERROR(ENOMEM);
249  }
250 
251 // SUGGESTION
252 // Now that avcodec_decode_audio4 is deprecated and replaced
253 // by 2 calls (receive frame and send packet), this could be optimized
254 // into separate routines or separate threads.
255 // Also now that it always consumes a whole buffer some code
256 // in the caller may be able to be optimized.
257  int ret = avcodec_receive_frame(ctx,frame);
258  if (ret == 0)
259  got_frame = true;
260  if (ret == AVERROR(EAGAIN))
261  ret = 0;
262  if (ret == 0)
263  ret = avcodec_send_packet(ctx, pkt);
264  if (ret == AVERROR(EAGAIN))
265  ret = 0;
266  else if (ret < 0)
267  {
268  std::string error;
269  LOG(VB_AUDIO, LOG_ERR, LOC +
270  QString("audio decode error: %1 (%2)")
271  .arg(av_make_error_stdstring(error, ret))
272  .arg(got_frame));
273  return ret;
274  }
275  else
276  ret = pkt->size;
277 
278  if (!got_frame)
279  {
280  LOG(VB_AUDIO, LOG_DEBUG, LOC +
281  QString("audio decode, no frame decoded (%1)").arg(ret));
282  return ret;
283  }
284 
285  auto format = (AVSampleFormat)frame->format;
286 
287  data_size = frame->nb_samples * frame->ch_layout.nb_channels * av_get_bytes_per_sample(format);
288 
289  if (av_sample_fmt_is_planar(format))
290  {
291  InterleaveSamples(AudioOutputSettings::AVSampleFormatToFormat(format, ctx->bits_per_raw_sample),
292  frame->ch_layout.nb_channels, buffer, (const uint8_t **)frame->extended_data,
293  data_size);
294  }
295  else
296  {
297  // data is already compacted... simply copy it
298  memcpy(buffer, frame->extended_data[0], data_size);
299  }
300 
301  return ret;
302 }
303 
309  uint8_t *output, const uint8_t *input,
310  int data_size)
311 {
312  AudioConvert::DeinterleaveSamples(format, channels, output, input, data_size);
313 }
314 
321  uint8_t *output, const uint8_t * const *input,
322  int data_size)
323 {
324  AudioConvert::InterleaveSamples(format, channels, output, input, data_size);
325 }
326 
332  uint8_t *output, const uint8_t *input,
333  int data_size)
334 {
335  AudioConvert::InterleaveSamples(format, channels, output, input, data_size);
336 }
AudioConvert::toFloat
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
Definition: audioconvert.cpp:522
AudioOutputSettings::AVSampleFormatToFormat
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
Definition: audiooutputsettings.cpp:198
pink.h
error
static void error(const char *str,...)
Definition: vbi.cpp:36
audiooutpututil.h
AudioOutputUtil::GeneratePinkFrames
static char * GeneratePinkFrames(char *frames, int channels, int channel, int count, int bits=16)
Definition: audiooutpututil.cpp:194
AudioOutputUtil::toFloat
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
Definition: audiooutpututil.cpp:72
MythAVFrame
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
Definition: mythaverror.h:52
AudioConvert::fromFloat
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
Definition: audioconvert.cpp:552
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
AudioOutputUtil::MonoToStereo
static void MonoToStereo(void *dst, const void *src, int samples)
Convert a mono stream to stereo by copying and interleaving samples.
Definition: audiooutpututil.cpp:92
AudioOutputUtil::DecodeAudio
static int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
DecodeAudio Decode an audio packet, and compact it if data is planar Return negative error code if an...
Definition: audiooutpututil.cpp:238
mythlogging.h
AudioConvert::DeinterleaveSamples
void DeinterleaveSamples(int channels, uint8_t *output, const uint8_t *input, int data_size)
Definition: audioconvert.cpp:876
initialize_pink_noise
void initialize_pink_noise(pink_noise_t *pink, int num_rows)
Definition: pink.cpp:41
LOC
#define LOC
Definition: audiooutpututil.cpp:19
AudioConvert::MonoToStereo
static void MonoToStereo(void *dst, const void *src, int samples)
Convert a mono stream to stereo by copying and interleaving samples.
Definition: audioconvert.cpp:728
tMuteChannel
void tMuteChannel(AudioDataType *buffer, int channels, int ch, int frames)
Definition: audiooutpututil.cpp:162
AudioOutputUtil::InterleaveSamples
static void InterleaveSamples(AudioFormat format, int channels, uint8_t *output, const uint8_t *const *input, int data_size)
Interleave input samples Planar audio is contained in array of pointers Interleave audio samples (con...
Definition: audiooutpututil.cpp:320
musicbrainzngs.compat.bytes
bytes
Definition: compat.py:49
AudioOutputUtil::has_optimized_SIMD
static bool has_optimized_SIMD()
Returns true if the processor supports MythTV's optimized SIMD for AudioOutputUtil/AudioConvert.
Definition: audiooutpututil.cpp:58
AudioOutputUtil::AdjustVolume
static void AdjustVolume(void *buffer, int len, int volume, bool music, bool upmix)
Adjust the volume of samples.
Definition: audiooutpututil.cpp:103
generate_pink_noise_sample
float generate_pink_noise_sample(pink_noise_t *pink)
Definition: pink.cpp:56
pink_noise_t
Definition: pink.h:12
AudioOutputUtil::DeinterleaveSamples
static void DeinterleaveSamples(AudioFormat format, int channels, uint8_t *output, const uint8_t *input, int data_size)
Deinterleave input samples Deinterleave audio samples and compact them.
Definition: audiooutpututil.cpp:308
AudioConvert::InterleaveSamples
void InterleaveSamples(int channels, uint8_t *output, const uint8_t *const *input, int data_size)
Definition: audioconvert.cpp:883
AudioOutputUtil::fromFloat
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
Definition: audiooutpututil.cpp:83
AudioFormat
AudioFormat
Definition: audiooutputsettings.h:24
output
#define output
Definition: synaesthesia.cpp:220
samples
static const std::array< const uint64_t, 4 > samples
Definition: element.cpp:46
AudioOutputUtil::MuteChannel
static void MuteChannel(int obits, int channels, int ch, void *buffer, int bytes)
Mute individual channels through mono->stereo duplication.
Definition: audiooutpututil.cpp:181
mythaverror.h
av_make_error_stdstring
char * av_make_error_stdstring(std::string &errbuf, int errnum)
Definition: mythaverror.cpp:41
audioconvert.h