Skip to content

Commit

Permalink
Add AudioOutputUtil::InterleaveSamples method.
Browse files Browse the repository at this point in the history
Will allow to convert planar audio into interleaved. Currently using FFmpeg's SWR_CONVERT which has a much more extensive range of capabilities.
AudioOutputUtil::InterleaveSamples doesn't need to allocate memory, and is much faster and simpler for this straightforward task.
  • Loading branch information
jyavenard committed Jun 6, 2013
1 parent 38f6c3a commit 7e9c9d0
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 51 deletions.
137 changes: 88 additions & 49 deletions mythtv/libs/libmyth/audio/audiooutpututil.cpp
Expand Up @@ -681,7 +681,7 @@ char *AudioOutputUtil::GeneratePinkFrames(char *frames, int channels,
*samp32++ = 0;
}
}
}
}
return frames;
}

Expand All @@ -694,7 +694,7 @@ char *AudioOutputUtil::GeneratePinkFrames(char *frames, int channels,
*/
int AudioOutputUtil::DecodeAudio(AVCodecContext *ctx,
uint8_t *buffer, int &data_size,
AVPacket *pkt)
const AVPacket *pkt)
{
AVFrame frame;
int got_frame = 0;
Expand Down Expand Up @@ -728,55 +728,13 @@ int AudioOutputUtil::DecodeAudio(AVCodecContext *ctx,
frame.nb_samples,
format, 1);
memcpy(buffer, frame.extended_data[0], data_size);
return ret;
}

// Need to find a valid channels layout, as not all codecs provide one
int64_t channel_layout =
frame.channel_layout && frame.channels == av_get_channel_layout_nb_channels(frame.channel_layout) ?
frame.channel_layout : av_get_default_channel_layout(frame.channels);
SwrContext *swr = swr_alloc_set_opts(NULL,
channel_layout,
av_get_packed_sample_fmt(format),
frame.sample_rate,
channel_layout,
format,
frame.sample_rate,
0, NULL);
if (!swr)
{
LOG(VB_AUDIO, LOG_ERR, LOC + "error allocating resampler context");
return AVERROR(ENOMEM);
}
/* initialize the resampling context */
ret2 = swr_init(swr);
if (ret2 < 0)
{
LOG(VB_AUDIO, LOG_ERR, LOC +
QString("error initializing resampler context (%1)")
.arg(av_make_error_string(error, sizeof(error), ret2)));
swr_free(&swr);
return ret2;
}

uint8_t *out[] = {buffer};
ret2 = swr_convert(swr, out, frame.nb_samples,
(const uint8_t **)frame.extended_data, frame.nb_samples);
swr_free(&swr);
if (ret2 < 0)
{
LOG(VB_AUDIO, LOG_ERR, LOC +
QString("error converting audio from planar format (%1)")
.arg(av_make_error_string(error, sizeof(error), ret2)));
return ret2;
}
data_size = ret2 * frame.channels * av_get_bytes_per_sample(format);

return ret;
}

template <class AudioDataType>
void _DeinterleaveSample(AudioDataType *out, AudioDataType *in, int channels, int frames)
void _DeinterleaveSample(AudioDataType *out, const AudioDataType *in, int channels, int frames)
{
AudioDataType *outp[8];

Expand All @@ -799,20 +757,101 @@ void _DeinterleaveSample(AudioDataType *out, AudioDataType *in, int channels, in
* Deinterleave audio samples and compact them
*/
void AudioOutputUtil::DeinterleaveSamples(AudioFormat format, int channels,
uint8_t *output, uint8_t *input,
uint8_t *output, const uint8_t *input,
int data_size)
{
int bits = AudioOutputSettings::FormatToBits(format);
if (bits == 8)
{
_DeinterleaveSample((char *)output, (char *)input, channels, data_size/sizeof(char)/channels);
_DeinterleaveSample((char *)output, (const char *)input, channels, data_size/sizeof(char)/channels);
}
else if (bits == 16)
{
_DeinterleaveSample((short *)output, (const short *)input, channels, data_size/sizeof(short)/channels);
}
else
{
_DeinterleaveSample((int *)output, (const int *)input, channels, data_size/sizeof(int)/channels);
}
}

template <class AudioDataType>
void _InterleaveSample(AudioDataType *out, const AudioDataType *in, int channels, int frames,
const AudioDataType * const *inp = NULL)
{
const AudioDataType *my_inp[8];

if (!inp)
{
// We're given an array of int, calculate pointers to each row
for (int i = 0; i < channels; i++)
{
my_inp[i] = in + (i * channels * frames);
}
}
else
{
for (int i = 0; i < channels; i++)
{
my_inp[i] = inp[i];
}
}

for (int i = 0; i < frames; i++)
{
for (int j = 0; j < channels; j++)
{
*(out++) = *(my_inp[j]++);
}
}
}

/**
* Interleave input samples
* Planar audio is contained in array of pointers
* Interleave audio samples (convert from planar format)
*/
void AudioOutputUtil::InterleaveSamples(AudioFormat format, int channels,
uint8_t *output, const uint8_t * const *input,
int data_size)
{
int bits = AudioOutputSettings::FormatToBits(format);
if (bits == 8)
{
_InterleaveSample((char *)output, (const char *)NULL, channels, data_size/sizeof(char)/channels,
(const char * const *)input);
}
else if (bits == 16)
{
_InterleaveSample((short *)output, (const short *)NULL, channels, data_size/sizeof(short)/channels,
(const short * const *)input);
}
else
{
_InterleaveSample((int *)output, (const int *)NULL, channels, data_size/sizeof(int)/channels,
(const int * const *)input);
}
}

/**
* Interleave input samples
* Interleave audio samples (convert from planar format)
*/
void AudioOutputUtil::InterleaveSamples(AudioFormat format, int channels,
uint8_t *output, const uint8_t *input,
int data_size)
{
int bits = AudioOutputSettings::FormatToBits(format);
if (bits == 8)
{
_InterleaveSample((char *)output, (const char *)input, channels, data_size/sizeof(char)/channels);
}
else if (bits == 16)
{
_DeinterleaveSample((short *)output, (short *)input, channels, data_size/sizeof(short)/channels);
_InterleaveSample((short *)output, (const short *)input, channels, data_size/sizeof(short)/channels);
}
else
{
_DeinterleaveSample((int *)output, (int *)input, channels, data_size/sizeof(int)/channels);
_InterleaveSample((int *)output, (const int *)input, channels, data_size/sizeof(int)/channels);
}
}
10 changes: 8 additions & 2 deletions mythtv/libs/libmyth/audio/audiooutpututil.h
Expand Up @@ -18,10 +18,16 @@ class MPUBLIC AudioOutputUtil
int channel, int count, int bits = 16);
static int DecodeAudio(AVCodecContext *ctx,
uint8_t *buffer, int &data_size,
AVPacket *pkt);
const AVPacket *pkt);
static void DeinterleaveSamples(AudioFormat format, int channels,
uint8_t *output, uint8_t *input,
uint8_t *output, const uint8_t *input,
int data_size);
static void InterleaveSamples(AudioFormat format, int channels,
uint8_t *output, const uint8_t * const *input,
int data_size);
static void InterleaveSamples(AudioFormat format, int channels,
uint8_t *output, const uint8_t *input,
int data_size);
};

#endif

0 comments on commit 7e9c9d0

Please sign in to comment.