summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-11-11 12:08:23 +0100
committerwm4 <wm4@nowhere>2013-11-12 23:34:49 +0100
commit6f557aef423e06a02a4992f2bf1201e08c9453b4 (patch)
treebd6e95999e87d67ae0e8ae39668a6c062abb29e3
parenta72072c6059d8c9661e58346359231c694ced968 (diff)
downloadmpv-6f557aef423e06a02a4992f2bf1201e08c9453b4.tar.bz2
mpv-6f557aef423e06a02a4992f2bf1201e08c9453b4.tar.xz
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.
-rw-r--r--audio/filter/af_lavcac3enc.c216
1 files changed, 82 insertions, 134 deletions
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
index de7d563b76..dc2aeb5045 100644
--- a/audio/filter/af_lavcac3enc.c
+++ b/audio/filter/af_lavcac3enc.c
@@ -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;
-
- 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 num_frames = (audio->samples + mp_audio_buffer_samples(s->pending))
+ / s->in_samples;
- mp_audio_realloc_min(af->data, max_output_len / af->data->sstride);
- af->data->samples = max_output_len / af->data->sstride;
+ int max_out_samples = s->out_samples * num_frames;
+ mp_audio_realloc_min(out, max_out_samples);
+ out->samples = 0;
- 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;
- break;
- }
-
- 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;
+ 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);
}
- 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;
+ mp_audio_buffer_peek(s->pending, &in_frame);
+ if (in_frame.samples < s->in_samples)
+ break;
+ consumed_pending = s->in_samples;
}
+ 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);
- int bsmod = s->pkt.data[5] & 0x7;
+ char hdr[8];
- 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
+ if (s->add_iec61937_header && s->pkt.size > 5) {
+ int bsmod = s->pkt.data[5] & 0x7;
+ int len = frame_size;
- 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) {
- 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;
+ 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];
- 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;
}
}
+ if (!s->in_sampleformat) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, encoder doesn't "
+ "support expected sample formats!\n");
+ return AF_ERROR;
+ }
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;
}