af_lavcac3enc: use planar formats

Remove the awkward planarization. It had to be done because the AC3
encoder requires planar formats, but now we support them natively.

Try to simplify buffer management with mp_audio_buffer.

Improve checking for buffer overflows and out of bound writes. In
theory, these shouldn't happen due to AC3 fixed frame sizes, but being
paranoid is better.
This commit is contained in:
wm4 2013-11-11 12:08:23 +01:00
parent a72072c605
commit 6f557aef42
1 changed files with 82 additions and 134 deletions

View File

@ -34,7 +34,8 @@
#include "config.h"
#include "af.h"
#include "audio/reorder_ch.h"
#include "audio/audio_buffer.h"
#include "audio/fmt-conversion.h"
#define AC3_MAX_CHANNELS 6
@ -53,10 +54,9 @@ typedef struct af_ac3enc_s {
bool planarize;
int add_iec61937_header;
int bit_rate;
int pending_data_size;
char *pending_data;
int pending_len;
int expect_len;
struct mp_audio_buffer *pending;
int in_samples; // samples of input per AC3 frame
int out_samples; // upper bound on encoded output per AC3 frame
int min_channel_num;
int in_sampleformat;
} af_ac3enc_t;
@ -93,17 +93,18 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (!mp_audio_config_equals(in, &orig_in))
return AF_FALSE;
s->pending_len = 0;
int expect_samples = AC3_FRAME_SIZE;
s->expect_len = expect_samples * in->nch * in->bps;
assert(s->expect_len <= s->pending_data_size);
if (s->add_iec61937_header)
af->mul = 1;
else
af->mul = (double)(AC3_MAX_CODED_FRAME_SIZE / (2 * 2)) / expect_samples;
s->in_samples = AC3_FRAME_SIZE;
if (s->add_iec61937_header) {
s->out_samples = AC3_FRAME_SIZE;
} else {
s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride;
}
af->mul = s->out_samples / (double)s->in_samples;
mp_audio_buffer_reinit(s->pending, in);
mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc reinit: %d, %d, %f, %d.\n",
in->nch, in->rate, af->mul, s->expect_len);
in->nch, in->rate, af->mul, s->in_samples);
bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch];
@ -172,83 +173,56 @@ static void uninit(struct af_instance* af)
avcodec_close(s->lavc_actx);
av_free(s->lavc_actx);
}
free(s->pending_data);
free(s);
}
}
// Filter data through filter
static struct mp_audio* play(struct af_instance* af, struct mp_audio* audio)
{
struct mp_audio *out = af->data;
af_ac3enc_t *s = af->setup;
struct mp_audio *c = audio; // Current working data
struct mp_audio *l;
int left, outsize = 0;
char *buf, *src;
int max_output_len;
int frame_num = (mp_audio_psize(audio) + s->pending_len) / s->expect_len;
int samplesize = af_fmt2bits(s->in_sampleformat) / 8;
int num_frames = (audio->samples + mp_audio_buffer_samples(s->pending))
/ s->in_samples;
if (s->add_iec61937_header)
max_output_len = AC3_FRAME_SIZE * 2 * 2 * frame_num;
else
max_output_len = AC3_MAX_CODED_FRAME_SIZE * frame_num;
int max_out_samples = s->out_samples * num_frames;
mp_audio_realloc_min(out, max_out_samples);
out->samples = 0;
mp_audio_realloc_min(af->data, max_output_len / af->data->sstride);
af->data->samples = max_output_len / af->data->sstride;
l = af->data; // Local data
buf = l->planes[0];
src = c->planes[0];
left = mp_audio_psize(c);
while (left > 0) {
while (audio->samples > 0) {
int ret;
if (left + s->pending_len < s->expect_len) {
memcpy(s->pending_data + s->pending_len, src, left);
src += left;
s->pending_len += left;
left = 0;
int consumed_pending = 0;
struct mp_audio in_frame;
int pending = mp_audio_buffer_samples(s->pending);
if (pending == 0 && audio->samples >= s->in_samples) {
in_frame = *audio;
mp_audio_skip_samples(audio, s->in_samples);
} else {
if (pending > 0 && pending < s->in_samples) {
struct mp_audio tmp = *audio;
tmp.samples = MPMIN(tmp.samples, s->in_samples);
mp_audio_buffer_append(s->pending, &tmp);
mp_audio_skip_samples(audio, tmp.samples);
}
mp_audio_buffer_peek(s->pending, &in_frame);
if (in_frame.samples < s->in_samples)
break;
consumed_pending = s->in_samples;
}
char *src2 = src;
if (s->pending_len) {
int needs = s->expect_len - s->pending_len;
if (needs > 0) {
memcpy(s->pending_data + s->pending_len, src, needs);
src += needs;
left -= needs;
}
src2= s->pending_data;
}
void *data = (void *) src2;
if (s->planarize) {
void *data2 = malloc(s->expect_len);
reorder_to_planar(data2, data, samplesize,
c->nch, s->expect_len / samplesize / c->nch);
data = data2;
}
in_frame.samples = s->in_samples;
AVFrame *frame = avcodec_alloc_frame();
if (!frame) {
mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n");
return NULL;
}
frame->nb_samples = AC3_FRAME_SIZE;
frame->nb_samples = s->in_samples;
frame->format = s->lavc_actx->sample_fmt;
frame->channel_layout = s->lavc_actx->channel_layout;
ret = avcodec_fill_audio_frame(frame, c->nch, s->lavc_actx->sample_fmt,
(const uint8_t*)data, s->expect_len, 0);
if (ret < 0) {
mp_msg(MSGT_AFILTER, MSGL_FATAL, "[lavac3enc] Frame setup failed.\n");
return NULL;
}
assert(in_frame.num_planes <= AV_NUM_DATA_POINTERS);
for (int n = 0; n < in_frame.num_planes; n++)
frame->data[n] = in_frame.planes[n];
frame->linesize[0] = s->in_samples * audio->sstride;
int ok;
ret = avcodec_encode_audio2(s->lavc_actx, &s->pkt, frame, &ok);
@ -257,58 +231,52 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* audio)
return NULL;
}
if (s->planarize)
free(data);
avcodec_free_frame(&frame);
if (s->pending_len) {
s->pending_len = 0;
} else {
src += s->expect_len;
left -= s->expect_len;
}
mp_audio_buffer_skip(s->pending, consumed_pending);
mp_msg(MSGT_AFILTER, MSGL_DBG2, "avcodec_encode_audio got %d, pending %d.\n",
s->pkt.size, s->pending_len);
s->pkt.size, mp_audio_buffer_samples(s->pending));
int len = s->pkt.size;
int frame_size = s->pkt.size;
int header_len = 0;
if (s->add_iec61937_header) {
assert(s->pkt.size > 5);
char hdr[8];
if (s->add_iec61937_header && s->pkt.size > 5) {
int bsmod = s->pkt.data[5] & 0x7;
int len = frame_size;
AV_WB16(buf, 0xF872); // iec 61937 syncword 1
AV_WB16(buf + 2, 0x4E1F); // iec 61937 syncword 2
buf[4] = bsmod; // bsmod
buf[5] = 0x01; // data-type ac3
AV_WB16(buf + 6, len << 3); // number of bits in payload
memset(buf + 8 + len, 0, AC3_FRAME_SIZE * 2 * 2 - 8 - len);
frame_size = AC3_FRAME_SIZE * 2 * 2;
header_len = 8;
len = AC3_FRAME_SIZE * 2 * 2;
AV_WB16(hdr, 0xF872); // iec 61937 syncword 1
AV_WB16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
hdr[4] = bsmod; // bsmod
hdr[5] = 0x01; // data-type ac3
AV_WB16(hdr + 6, len << 3); // number of bits in payload
}
assert(buf + len <= (char *)af->data->planes[0] + mp_audio_psize(af->data));
assert(s->pkt.size <= len - header_len);
size_t max_size = (max_out_samples - out->samples) * out->sstride;
if (frame_size > max_size)
abort();
char *buf = (char *)out->planes[0] + out->samples * out->sstride;
memcpy(buf, hdr, header_len);
memcpy(buf + header_len, s->pkt.data, s->pkt.size);
outsize += len;
buf += len;
memset(buf + header_len + s->pkt.size, 0,
frame_size - (header_len + s->pkt.size));
out->samples += frame_size / out->sstride;
}
c->planes[0] = l->planes[0];
mp_audio_set_num_channels(c, 2);
mp_audio_set_format(c, af->data->format);
c->samples = outsize / c->sstride;
mp_msg(MSGT_AFILTER, MSGL_DBG2, "play return size %d, pending %d\n",
outsize, s->pending_len);
return c;
mp_audio_buffer_append(s->pending, audio);
*audio = *out;
return audio;
}
static int af_open(struct af_instance* af){
af_ac3enc_t *s = calloc(1,sizeof(af_ac3enc_t));
af_ac3enc_t *s = talloc_zero(af, af_ac3enc_t);
af->control=control;
af->uninit=uninit;
af->play=play;
@ -326,45 +294,25 @@ static int af_open(struct af_instance* af){
return AF_ERROR;
}
const enum AVSampleFormat *fmts = s->lavc_acodec->sample_fmts;
for (int i = 0; ; i++) {
if (fmts[i] == AV_SAMPLE_FMT_NONE) {
for (int i = 0; fmts[i] != AV_SAMPLE_FMT_NONE; i++) {
s->in_sampleformat = af_from_avformat(fmts[i]);
if (s->in_sampleformat) {
s->lavc_actx->sample_fmt = fmts[i];
break;
}
}
if (!s->in_sampleformat) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, encoder doesn't "
"support expected sample formats!\n");
return AF_ERROR;
} else if (fmts[i] == AV_SAMPLE_FMT_S16) {
s->in_sampleformat = AF_FORMAT_S16_NE;
s->lavc_actx->sample_fmt = fmts[i];
s->planarize = 0;
break;
} else if (fmts[i] == AV_SAMPLE_FMT_FLT) {
s->in_sampleformat = AF_FORMAT_FLOAT_NE;
s->lavc_actx->sample_fmt = fmts[i];
s->planarize = 0;
break;
} else if (fmts[i] == AV_SAMPLE_FMT_S16P) {
s->in_sampleformat = AF_FORMAT_S16_NE;
s->lavc_actx->sample_fmt = fmts[i];
s->planarize = 1;
break;
} else if (fmts[i] == AV_SAMPLE_FMT_FLTP) {
s->in_sampleformat = AF_FORMAT_FLOAT_NE;
s->lavc_actx->sample_fmt = fmts[i];
s->planarize = 1;
break;
}
}
mp_msg(MSGT_AFILTER, MSGL_V, "[af_lavcac3enc]: in sample format: %s\n",
af_fmt_to_str(s->in_sampleformat));
s->pending_data_size = AF_NCH * AC3_FRAME_SIZE *
af_fmt2bits(s->in_sampleformat) / 8;
s->pending_data = malloc(s->pending_data_size);
if (s->planarize)
mp_msg(MSGT_AFILTER, MSGL_WARN,
"[af_lavcac3enc]: need to planarize audio data\n");
av_init_packet(&s->pkt);
s->pending = mp_audio_buffer_create(af);
return AF_OK;
}