Skip to content
Permalink
Browse files

Fix AC3 encoder following FFmpeg resync

AC3 encoder now expects planar audio data. This commit adds an utility method to de-interleave and convert interleaved data into planar data.

Fixes #11483
  • Loading branch information
jyavenard committed Apr 14, 2013
1 parent 1252fe5 commit 476b2a826d43fca5e658ebe787c3cb1ec2334f98
@@ -23,7 +23,7 @@ extern "C" {
AudioOutputDigitalEncoder::AudioOutputDigitalEncoder(void) :
av_context(NULL),
out(NULL), out_size(0),
in(NULL), in_size(0),
in(NULL), inp(NULL), in_size(0),
outlen(0), inlen(0),
samples_per_frame(0),
m_spdifenc(NULL)
@@ -38,6 +38,7 @@ AudioOutputDigitalEncoder::AudioOutputDigitalEncoder(void) :
{
in_size = INBUFSIZE;
}
inp = (inbuf_t *)av_malloc(INBUFSIZE);
}

AudioOutputDigitalEncoder::~AudioOutputDigitalEncoder()
@@ -62,6 +63,10 @@ void AudioOutputDigitalEncoder::Dispose()
av_freep(&in);
in_size = 0;
}
if (inp)
{
av_freep(&inp);
}
if (m_spdifenc)
{
delete m_spdifenc;
@@ -136,7 +141,7 @@ bool AudioOutputDigitalEncoder::Init(
av_context->channel_layout = AV_CH_LAYOUT_5POINT1;
break;
}
av_context->sample_fmt = AV_SAMPLE_FMT_S16;
av_context->sample_fmt = AV_SAMPLE_FMT_S16P;

// open it
ret = avcodec_open2(av_context, codec, NULL);
@@ -205,20 +210,35 @@ size_t AudioOutputDigitalEncoder::Encode(void *buf, int len, AudioFormat format)
inlen += len;
}

int frames = inlen / sizeof(inbuf_t) / samples_per_frame;
int i = 0;
AVFrame *frame = avcodec_alloc_frame();
int frames = inlen / sizeof(inbuf_t) / samples_per_frame;
int i = 0;
int channels = av_context->channels;
AVFrame *frame = avcodec_alloc_frame();
int size_channel = av_context->frame_size *
AudioOutputSettings::SampleSize(FORMAT_S16);
frame->extended_data = frame->data;
frame->nb_samples = av_context->frame_size;
frame->pts = AV_NOPTS_VALUE;
// init AVFrame for planar data (input is interleaved)
for (int j = 0, jj = 0; j < channels; j++, jj += samples_per_frame)
{
frame->data[j] = (uint8_t*)(inp + jj);
}

while (i < frames)
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = (uint8_t *)m_encodebuffer;
pkt.size = sizeof(m_encodebuffer);
frame->nb_samples = av_context->frame_size;
frame->data[0] = (uint8_t *)(in + i * samples_per_frame);
frame->pts = AV_NOPTS_VALUE;
int got_packet = 0;

AudioOutputUtil::DeinterleaveSamples(
FORMAT_S16, channels,
(uint8_t*)inp,
(uint8_t*)(in + i * samples_per_frame),
size_channel * channels);

int ret = avcodec_encode_audio2(av_context, &pkt, frame,
&got_packet);
int outsize = pkt.size;
@@ -34,7 +34,7 @@ class AudioOutputDigitalEncoder
AVCodecContext *av_context;
outbuf_t *out;
size_t out_size;
inbuf_t *in;
inbuf_t *in, *inp;
size_t in_size;
int outlen;
int inlen;
@@ -767,3 +767,45 @@ int AudioOutputUtil::DecodeAudio(AVCodecContext *ctx,

return ret;
}

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

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

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

/**
* Deinterleave input samples
* Deinterleave audio samples and compact them
*/
void AudioOutputUtil::DeinterleaveSamples(AudioFormat format, int channels,
uint8_t *output, 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);
}
else if (bits == 16)
{
_DeinterleaveSample((short *)output, (short *)input, channels, data_size/sizeof(short)/channels);
}
else
{
_DeinterleaveSample((int *)output, (int *)input, channels, data_size/sizeof(int)/channels);
}
}
@@ -19,6 +19,9 @@ class MPUBLIC AudioOutputUtil
static int DecodeAudio(AVCodecContext *ctx,
uint8_t *buffer, int &data_size,
AVPacket *pkt);
static void DeinterleaveSamples(AudioFormat format, int channels,
uint8_t *output, uint8_t *input,
int data_size);
};

#endif

0 comments on commit 476b2a8

Please sign in to comment.
You can’t perform that action at this time.