Skip to content

Commit

Permalink
Fix AC3 encoder following FFmpeg resync
Browse files Browse the repository at this point in the history
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 476b2a8
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 9 deletions.
36 changes: 28 additions & 8 deletions mythtv/libs/libmyth/audio/audiooutputdigitalencoder.cpp
Expand Up @@ -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)
Expand All @@ -38,6 +38,7 @@ AudioOutputDigitalEncoder::AudioOutputDigitalEncoder(void) :
{
in_size = INBUFSIZE;
}
inp = (inbuf_t *)av_malloc(INBUFSIZE);
}

AudioOutputDigitalEncoder::~AudioOutputDigitalEncoder()
Expand All @@ -62,6 +63,10 @@ void AudioOutputDigitalEncoder::Dispose()
av_freep(&in);
in_size = 0;
}
if (inp)
{
av_freep(&inp);
}
if (m_spdifenc)
{
delete m_spdifenc;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmyth/audio/audiooutputdigitalencoder.h
Expand Up @@ -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;
Expand Down
42 changes: 42 additions & 0 deletions mythtv/libs/libmyth/audio/audiooutpututil.cpp
Expand Up @@ -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);
}
}
3 changes: 3 additions & 0 deletions mythtv/libs/libmyth/audio/audiooutpututil.h
Expand Up @@ -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.