MythTV  master
audiooutpututil.cpp
Go to the documentation of this file.
1 #include <cinttypes>
2 #include <cmath>
3 #include <sys/types.h>
4 
5 #include "mythconfig.h"
6 #include "mythlogging.h"
7 #include "audiooutpututil.h"
8 #include "audioconvert.h"
9 #include "bswap.h"
10 #include "mythaverror.h"
11 
12 extern "C" {
13 #include "libavcodec/avcodec.h"
14 }
15 #include "pink.h"
16 
17 #define LOC QString("AOUtil: ")
18 
19 #define ISALIGN(x) (((unsigned long)(x) & 0xf) == 0)
20 
21 #if ARCH_X86
22 static int has_sse2 = -1;
23 
24 // Check cpuid for SSE2 support on x86 / x86_64
25 static inline bool sse_check()
26 {
27  if (has_sse2 != -1)
28  return (bool)has_sse2;
29  __asm__(
30  // -fPIC - we may not clobber ebx/rbx
31 #if ARCH_X86_64
32  "push %%rbx \n\t"
33 #else
34  "push %%ebx \n\t"
35 #endif
36  "mov $1, %%eax \n\t"
37  "cpuid \n\t"
38  "and $0x4000000, %%edx \n\t"
39  "shr $26, %%edx \n\t"
40 #if ARCH_X86_64
41  "pop %%rbx \n\t"
42 #else
43  "pop %%ebx \n\t"
44 #endif
45  :"=d"(has_sse2)
46  ::"%eax","%ecx"
47  );
48  return (bool)has_sse2;
49 }
50 #endif //ARCH_x86
51 
57 {
58 #if ARCH_X86
59  return sse_check();
60 #else
61  return false;
62 #endif
63 }
64 
70 int AudioOutputUtil::toFloat(AudioFormat format, void *out, const void *in,
71  int bytes)
72 {
73  return AudioConvert::toFloat(format, out, in, bytes);
74 }
75 
81 int AudioOutputUtil::fromFloat(AudioFormat format, void *out, const void *in,
82  int bytes)
83 {
84  return AudioConvert::fromFloat(format, out, in, bytes);
85 }
86 
90 void AudioOutputUtil::MonoToStereo(void *dst, const void *src, int samples)
91 {
93 }
94 
101 void AudioOutputUtil::AdjustVolume(void *buf, int len, int volume,
102  bool music, bool upmix)
103 {
104  float g = volume / 100.0F;
105  auto *fptr = (float *)buf;
106  int samples = len >> 2;
107  int i = 0;
108 
109  // Should be exponential - this'll do
110  g *= g;
111 
112  // Try to ~ match stereo volume when upmixing
113  if (upmix)
114  g *= 1.5F;
115 
116  // Music is relatively loud
117  if (music)
118  g *= 0.4F;
119 
120  if (g == 1.0F)
121  return;
122 
123 #if ARCH_X86
124  if (sse_check() && samples >= 16)
125  {
126  int loops = samples >> 4;
127  i = loops << 4;
128 
129  __asm__ volatile (
130  "movss %2, %%xmm0 \n\t"
131  "punpckldq %%xmm0, %%xmm0 \n\t"
132  "punpckldq %%xmm0, %%xmm0 \n\t"
133  "1: \n\t"
134  "movups (%0), %%xmm1 \n\t"
135  "movups 16(%0), %%xmm2 \n\t"
136  "mulps %%xmm0, %%xmm1 \n\t"
137  "movups 32(%0), %%xmm3 \n\t"
138  "mulps %%xmm0, %%xmm2 \n\t"
139  "movups 48(%0), %%xmm4 \n\t"
140  "mulps %%xmm0, %%xmm3 \n\t"
141  "movups %%xmm1, (%0) \n\t"
142  "mulps %%xmm0, %%xmm4 \n\t"
143  "movups %%xmm2, 16(%0) \n\t"
144  "movups %%xmm3, 32(%0) \n\t"
145  "movups %%xmm4, 48(%0) \n\t"
146  "add $64, %0 \n\t"
147  "sub $1, %%ecx \n\t"
148  "jnz 1b \n\t"
149  :"+r"(fptr)
150  :"c"(loops),"m"(g)
151  :"xmm0","xmm1","xmm2","xmm3","xmm4"
152  );
153  }
154 #endif //ARCH_X86
155  for (; i < samples; i++)
156  *fptr++ *= g;
157 }
158 
159 template <class AudioDataType>
160 void tMuteChannel(AudioDataType *buffer, int channels, int ch, int frames)
161 {
162  AudioDataType *s1 = buffer + ch;
163  AudioDataType *s2 = buffer - ch + 1;
164 
165  for (int i = 0; i < frames; i++)
166  {
167  *s1 = *s2;
168  s1 += channels;
169  s2 += channels;
170  }
171 }
172 
179 void AudioOutputUtil::MuteChannel(int obits, int channels, int ch,
180  void *buffer, int bytes)
181 {
182  int frames = bytes / ((obits >> 3) * channels);
183 
184  if (obits == 8)
185  tMuteChannel((uchar *)buffer, channels, ch, frames);
186  else if (obits == 16)
187  tMuteChannel((short *)buffer, channels, ch, frames);
188  else
189  tMuteChannel((int *)buffer, channels, ch, frames);
190 }
191 
192 #if HAVE_BIGENDIAN
193 #define LE_SHORT(v) bswap_16(v)
194 #define LE_INT(v) bswap_32(v)
195 #else
196 #define LE_SHORT(v) (v)
197 #define LE_INT(v) (v)
198 #endif
199 
200 char *AudioOutputUtil::GeneratePinkFrames(char *frames, int channels,
201  int channel, int count, int bits)
202 {
203  pink_noise_t pink{};
204 
205  initialize_pink_noise(&pink);
206 
207  auto *samp16 = (int16_t*) frames;
208  auto *samp32 = (int32_t*) frames;
209 
210  while (count-- > 0)
211  {
212  for(int chn = 0 ; chn < channels; chn++)
213  {
214  if (chn==channel)
215  {
216  /* Don't use MAX volume */
217  double res = generate_pink_noise_sample(&pink) *
218  static_cast<float>(0x03fffffff);
219  int32_t ires = res;
220  if (bits == 16)
221  *samp16++ = LE_SHORT(ires >> 16);
222  else
223  *samp32++ = LE_INT(ires);
224  }
225  else
226  {
227  if (bits == 16)
228  *samp16++ = 0;
229  else
230  *samp32++ = 0;
231  }
232  }
233  }
234  return frames;
235 }
236 
244 int AudioOutputUtil::DecodeAudio(AVCodecContext *ctx,
245  uint8_t *buffer, int &data_size,
246  const AVPacket *pkt)
247 {
248  MythAVFrame frame;
249  bool got_frame = false;
250 
251  data_size = 0;
252  if (!frame)
253  {
254  return AVERROR(ENOMEM);
255  }
256 
257 // SUGGESTION
258 // Now that avcodec_decode_audio4 is deprecated and replaced
259 // by 2 calls (receive frame and send packet), this could be optimized
260 // into separate routines or separate threads.
261 // Also now that it always consumes a whole buffer some code
262 // in the caller may be able to be optimized.
263  int ret = avcodec_receive_frame(ctx,frame);
264  if (ret == 0)
265  got_frame = true;
266  if (ret == AVERROR(EAGAIN))
267  ret = 0;
268  if (ret == 0)
269  ret = avcodec_send_packet(ctx, pkt);
270  if (ret == AVERROR(EAGAIN))
271  ret = 0;
272  else if (ret < 0)
273  {
274  std::string error;
275  LOG(VB_AUDIO, LOG_ERR, LOC +
276  QString("audio decode error: %1 (%2)")
278  .arg(got_frame));
279  return ret;
280  }
281  else
282  ret = pkt->size;
283 
284  if (!got_frame)
285  {
286  LOG(VB_AUDIO, LOG_DEBUG, LOC +
287  QString("audio decode, no frame decoded (%1)").arg(ret));
288  return ret;
289  }
290 
291  auto format = (AVSampleFormat)frame->format;
292 
293  data_size = frame->nb_samples * frame->channels * av_get_bytes_per_sample(format);
294 
295  if (av_sample_fmt_is_planar(format))
296  {
297  InterleaveSamples(AudioOutputSettings::AVSampleFormatToFormat(format, ctx->bits_per_raw_sample),
298  frame->channels, buffer, (const uint8_t **)frame->extended_data,
299  data_size);
300  }
301  else
302  {
303  // data is already compacted... simply copy it
304  memcpy(buffer, frame->extended_data[0], data_size);
305  }
306 
307  return ret;
308 }
309 
315  uint8_t *output, const uint8_t *input,
316  int data_size)
317 {
318  AudioConvert::DeinterleaveSamples(format, channels, output, input, data_size);
319 }
320 
327  uint8_t *output, const uint8_t * const *input,
328  int data_size)
329 {
330  AudioConvert::InterleaveSamples(format, channels, output, input, data_size);
331 }
332 
338  uint8_t *output, const uint8_t *input,
339  int data_size)
340 {
341  AudioConvert::InterleaveSamples(format, channels, output, input, data_size);
342 }
AudioConvert::toFloat
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
Definition: audioconvert.cpp:528
channel
QDomElement channel
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:501
AudioOutputSettings::AVSampleFormatToFormat
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
Definition: audiooutputsettings.cpp:197
pink.h
error
static void error(const char *str,...)
Definition: vbi.cpp:42
audiooutpututil.h
AudioOutputUtil::GeneratePinkFrames
static char * GeneratePinkFrames(char *frames, int channels, int channel, int count, int bits=16)
Definition: audiooutpututil.cpp:200
AudioOutputUtil::toFloat
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
Definition: audiooutpututil.cpp:70
MythAVFrame
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
Definition: mythaverror.h:53
arg
arg(title).arg(filename).arg(doDelete))
AudioConvert::fromFloat
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
Definition: audioconvert.cpp:558
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
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:90
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:244
mythlogging.h
LE_INT
#define LE_INT(v)
Definition: audiooutpututil.cpp:197
AudioConvert::DeinterleaveSamples
void DeinterleaveSamples(int channels, uint8_t *output, const uint8_t *input, int data_size)
Definition: audioconvert.cpp:877
AudioOutputUtil::has_hardware_fpu
static bool has_hardware_fpu()
Returns true if platform has an FPU.
Definition: audiooutpututil.cpp:56
initialize_pink_noise
void initialize_pink_noise(pink_noise_t *pink, int num_rows)
Definition: pink.cpp:41
LOC
#define LOC
Definition: audiooutpututil.cpp:17
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:729
tMuteChannel
void tMuteChannel(AudioDataType *buffer, int channels, int ch, int frames)
Definition: audiooutpututil.cpp:160
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:326
musicbrainzngs.compat.bytes
bytes
Definition: compat.py:49
AudioOutputUtil::AdjustVolume
static void AdjustVolume(void *buffer, int len, int volume, bool music, bool upmix)
Adjust the volume of samples.
Definition: audiooutpututil.cpp:101
bswap.h
generate_pink_noise_sample
float generate_pink_noise_sample(pink_noise_t *pink)
Definition: pink.cpp:56
pink_noise_t
Definition: pink.h:13
LE_SHORT
#define LE_SHORT(v)
Definition: audiooutpututil.cpp:196
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:314
AudioConvert::InterleaveSamples
void InterleaveSamples(int channels, uint8_t *output, const uint8_t *const *input, int data_size)
Definition: audioconvert.cpp:884
AudioOutputUtil::fromFloat
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
Definition: audiooutpututil.cpp:81
AudioFormat
AudioFormat
Definition: audiooutputsettings.h:25
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:179
mythaverror.h
av_make_error_stdstring
char * av_make_error_stdstring(std::string &errbuf, int errnum)
Definition: mythaverror.cpp:41
audioconvert.h