summaryrefslogtreecommitdiffstats
path: root/audio/filter/af_lavcac3enc.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-01-18 14:44:20 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-01-30 03:10:27 -0800
commitb9f804b566c4c528714e4ec5e63675ad7ba5fefd (patch)
tree49d6fcd42ce6597a67aa2af59b7f20beb21a2e14 /audio/filter/af_lavcac3enc.c
parent76276c92104c31ee936ba5c76a76072f09978c5f (diff)
downloadmpv-b9f804b566c4c528714e4ec5e63675ad7ba5fefd.tar.bz2
mpv-b9f804b566c4c528714e4ec5e63675ad7ba5fefd.tar.xz
audio: rewrite filtering glue code
Use the new filtering code for audio too.
Diffstat (limited to 'audio/filter/af_lavcac3enc.c')
-rw-r--r--audio/filter/af_lavcac3enc.c504
1 files changed, 229 insertions, 275 deletions
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
index 14aa53b980..c7582cf52b 100644
--- a/audio/filter/af_lavcac3enc.c
+++ b/audio/filter/af_lavcac3enc.c
@@ -31,14 +31,17 @@
#include <libavutil/bswap.h>
#include <libavutil/mem.h>
-#include "config.h"
-
-#include "common/av_common.h"
-#include "common/common.h"
-#include "af.h"
-#include "audio/audio_buffer.h"
+#include "audio/aframe.h"
#include "audio/chmap_sel.h"
#include "audio/fmt-conversion.h"
+#include "audio/format.h"
+#include "common/av_common.h"
+#include "common/common.h"
+#include "filters/f_autoconvert.h"
+#include "filters/f_utils.h"
+#include "filters/filter_internal.h"
+#include "filters/user_filters.h"
+#include "options/m_option.h"
#define AC3_MAX_CHANNELS 6
@@ -49,173 +52,89 @@ const uint16_t ac3_bitrate_tab[19] = {
160, 192, 224, 256, 320, 384, 448, 512, 576, 640
};
-// Data for specific instances of this filter
-typedef struct af_ac3enc_s {
+struct f_opts {
+ int add_iec61937_header;
+ int bit_rate;
+ int min_channel_num;
+ char *encoder;
+ char **avopts;
+};
+
+struct priv {
+ struct f_opts *opts;
+
+ struct mp_pin *in_pin;
+ struct mp_aframe *cur_format;
+ struct mp_aframe *in_frame;
+ struct mp_aframe_pool *out_pool;
+
struct AVCodec *lavc_acodec;
struct AVCodecContext *lavc_actx;
int bit_rate;
- struct mp_audio *input; // frame passed to libavcodec
- struct mp_audio *pending; // unconsumed input data
- int in_samples; // samples of input per AC3 frame
int out_samples; // upper bound on encoded output per AC3 frame
- int64_t encoder_buffered;
-
- int cfg_add_iec61937_header;
- int cfg_bit_rate;
- int cfg_min_channel_num;
- char *cfg_encoder;
- char **cfg_avopts;
-} af_ac3enc_t;
-
-// fmt carries the input format. Change it to the best next-possible format
-// the encoder likely accepts.
-static void select_encode_format(AVCodecContext *c, struct mp_audio *fmt)
-{
- int formats[AF_FORMAT_COUNT];
- af_get_best_sample_formats(fmt->format, formats);
-
- for (int n = 0; formats[n]; n++) {
- const enum AVSampleFormat *lf = c->codec->sample_fmts;
- for (int i = 0; lf && lf[i] != AV_SAMPLE_FMT_NONE; i++) {
- int mpfmt = af_from_avformat(lf[i]);
- if (mpfmt && mpfmt == formats[n]) {
- mp_audio_set_format(fmt, mpfmt);
- goto done_fmt;
- }
- }
- }
-done_fmt: ;
+};
- int rate =
- af_select_best_samplerate(fmt->rate, c->codec->supported_samplerates);
- if (rate > 0)
- fmt->rate = rate;
+static bool reinit(struct mp_filter *f)
+{
+ struct priv *s = f->priv;
- struct mp_chmap_sel sel = {0};
- const uint64_t *lch = c->codec->channel_layouts;
- for (int n = 0; lch && lch[n]; n++) {
- struct mp_chmap chmap = {0};
- mp_chmap_from_lavc(&chmap, lch[n]);
- mp_chmap_sel_add_map(&sel, &chmap);
- }
- struct mp_chmap res = fmt->channels;
- mp_chmap_sel_adjust(&sel, &res);
- if (!mp_chmap_is_empty(&res))
- mp_audio_set_channels(fmt, &res);
-}
+ mp_aframe_reset(s->cur_format);
-// Initialization and runtime control
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- af_ac3enc_t *s = af->priv;
static const int default_bit_rate[AC3_MAX_CHANNELS+1] = \
{0, 96000, 192000, 256000, 384000, 448000, 448000};
- switch (cmd){
- case AF_CONTROL_REINIT: {
- struct mp_audio *in = arg;
- struct mp_audio orig_in = *in;
-
- if (!af_fmt_is_pcm(in->format) || in->nch < s->cfg_min_channel_num)
- return AF_DETACH;
-
- // At least currently, the AC3 encoder doesn't export sample rates.
- in->rate = 48000;
- select_encode_format(s->lavc_actx, in);
-
- af->data->rate = in->rate;
- mp_audio_set_format(af->data, AF_FORMAT_S_AC3);
- mp_audio_set_num_channels(af->data, 2);
-
- if (!mp_audio_config_equals(in, &orig_in))
- return AF_FALSE;
-
- if (s->cfg_add_iec61937_header) {
- s->out_samples = AC3_FRAME_SIZE;
- } else {
- s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride;
- }
-
- mp_audio_copy_config(s->input, in);
-
- talloc_free(s->pending);
- s->pending = NULL;
-
- MP_DBG(af, "reinit: %d, %d, %d.\n", in->nch, in->rate, s->in_samples);
+ if (s->opts->add_iec61937_header) {
+ s->out_samples = AC3_FRAME_SIZE;
+ } else {
+ s->out_samples = AC3_MAX_CODED_FRAME_SIZE /
+ mp_aframe_get_sstride(s->in_frame);
+ }
- int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch];
+ int format = mp_aframe_get_format(s->in_frame);
+ int rate = mp_aframe_get_rate(s->in_frame);
+ struct mp_chmap chmap = {0};
+ mp_aframe_get_chmap(s->in_frame, &chmap);
- if (s->lavc_actx->channels != in->nch ||
- s->lavc_actx->sample_rate != in->rate ||
- s->lavc_actx->bit_rate != bit_rate)
- {
- avcodec_close(s->lavc_actx);
+ int bit_rate = s->bit_rate;
+ if (!bit_rate && chmap.num < AC3_MAX_CHANNELS + 1)
+ bit_rate = default_bit_rate[chmap.num];
- // Put sample parameters
- s->lavc_actx->sample_fmt = af_to_avformat(in->format);
- s->lavc_actx->channels = in->nch;
- s->lavc_actx->channel_layout = mp_chmap_to_lavc(&in->channels);
- s->lavc_actx->sample_rate = in->rate;
- s->lavc_actx->bit_rate = bit_rate;
+ avcodec_close(s->lavc_actx);
- if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) {
- MP_ERR(af, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate);
- return AF_ERROR;
- }
+ // Put sample parameters
+ s->lavc_actx->sample_fmt = af_to_avformat(format);
+ s->lavc_actx->channels = chmap.num;
+ s->lavc_actx->channel_layout = mp_chmap_to_lavc(&chmap);
+ s->lavc_actx->sample_rate = rate;
+ s->lavc_actx->bit_rate = bit_rate;
- if (s->lavc_actx->frame_size < 1) {
- MP_ERR(af, "encoder didn't specify input frame size\n");
- return AF_ERROR;
- }
- }
- s->in_samples = s->lavc_actx->frame_size;
- mp_audio_realloc(s->input, s->in_samples);
- s->input->samples = 0;
- s->encoder_buffered = 0;
- return AF_OK;
+ if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) {
+ MP_ERR(f, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate);
+ return false;
}
- case AF_CONTROL_RESET:
- if (avcodec_is_open(s->lavc_actx))
- avcodec_flush_buffers(s->lavc_actx);
- talloc_free(s->pending);
- s->pending = NULL;
- s->input->samples = 0;
- s->encoder_buffered = 0;
- return AF_OK;
- }
- return AF_UNKNOWN;
-}
-
-// Deallocate memory
-static void uninit(struct af_instance* af)
-{
- af_ac3enc_t *s = af->priv;
- if (s) {
- avcodec_free_context(&s->lavc_actx);
- talloc_free(s->pending);
+ if (s->lavc_actx->frame_size < 1) {
+ MP_ERR(f, "encoder didn't specify input frame size\n");
+ return false;
}
+
+ mp_aframe_config_copy(s->cur_format, s->in_frame);
+ return true;
}
-static void update_delay(struct af_instance *af)
+static void reset(struct mp_filter *f)
{
- af_ac3enc_t *s = af->priv;
- af->delay = ((s->pending ? s->pending->samples : 0) + s->input->samples +
- s->encoder_buffered) / (double)s->input->rate;
+ struct priv *s = f->priv;
+
+ TA_FREEP(&s->in_frame);
}
-static int filter_frame(struct af_instance *af, struct mp_audio *audio)
+static void destroy(struct mp_filter *f)
{
- af_ac3enc_t *s = af->priv;
+ struct priv *s = f->priv;
- // filter_output must have been called until no output was produced.
- if (s->pending && s->pending->samples)
- MP_ERR(af, "broken data flow\n");
-
- talloc_free(s->pending);
- s->pending = audio;
- update_delay(af);
- return 0;
+ reset(f);
+ avcodec_free_context(&s->lavc_actx);
}
static void swap_16(uint16_t *ptr, size_t size)
@@ -224,105 +143,84 @@ static void swap_16(uint16_t *ptr, size_t size)
ptr[n] = av_bswap16(ptr[n]);
}
-// Copy data from input frame to encode frame (because libavcodec wants a full
-// AC3 frame for encoding, while filter input frames can be smaller or larger).
-// Return true if the frame is complete.
-static bool fill_buffer(struct af_instance *af)
-{
- af_ac3enc_t *s = af->priv;
-
- af->delay = 0;
-
- if (s->pending) {
- if (!mp_audio_is_writeable(s->input))
- assert(s->input->samples == 0); // we can't have sent a partial frame
- mp_audio_realloc_min(s->input, s->in_samples);
- int copy = MPMIN(s->in_samples - s->input->samples, s->pending->samples);
- s->input->samples += copy;
- mp_audio_copy(s->input, s->input->samples - copy, s->pending, 0, copy);
- mp_audio_skip_samples(s->pending, copy);
- }
- update_delay(af);
- return s->input->samples >= s->in_samples;
-}
-
-// Return <0 on error, 0 on need more input, 1 on success (and *frame set).
-// To actually advance the read pointer, set s->input->samples=0 afterwards.
-static int read_input_frame(struct af_instance *af, AVFrame *frame)
+static void process(struct mp_filter *f)
{
- af_ac3enc_t *s = af->priv;
- if (!fill_buffer(af))
- return 0; // need more input
+ struct priv *s = f->priv;
- if (mp_audio_to_avframe(s->input, frame) < 0)
- return -1;
-
- return 1;
-}
-
-static int filter_out(struct af_instance *af)
-{
- af_ac3enc_t *s = af->priv;
-
- if (!s->pending)
- return 0;
-
- AVFrame *frame = av_frame_alloc();
- if (!frame) {
- MP_FATAL(af, "Could not allocate memory \n");
- return -1;
- }
- int err = -1;
+ if (!mp_pin_in_needs_data(f->ppins[1]))
+ return;
+ bool err = true;
+ struct mp_aframe *out = NULL;
AVPacket pkt = {0};
av_init_packet(&pkt);
// Send input as long as it wants.
while (1) {
- err = read_input_frame(af, frame);
- if (err < 0)
+ if (avcodec_is_open(s->lavc_actx)) {
+ int lavc_ret = avcodec_receive_packet(s->lavc_actx, &pkt);
+ if (lavc_ret >= 0)
+ break;
+ if (lavc_ret < 0 && lavc_ret != AVERROR(EAGAIN)) {
+ MP_FATAL(f, "Encode failed (receive).\n");
+ goto done;
+ }
+ }
+ AVFrame *frame = NULL;
+ struct mp_frame input = mp_pin_out_read(s->in_pin);
+ // The following code assumes no sample data buffering in the encoder.
+ if (input.type == MP_FRAME_EOF) {
+ mp_pin_in_write(f->ppins[1], input);
+ return;
+ } else if (input.type == MP_FRAME_AUDIO) {
+ TA_FREEP(&s->in_frame);
+ s->in_frame = input.data;
+ frame = mp_frame_to_av(input, NULL);
+ if (!frame)
+ goto done;
+ if (mp_aframe_get_channels(s->in_frame) < s->opts->min_channel_num) {
+ // Just pass it through.
+ s->in_frame = NULL;
+ mp_pin_in_write(f->ppins[1], input);
+ return;
+ }
+ if (!mp_aframe_config_equals(s->in_frame, s->cur_format)) {
+ if (!reinit(f))
+ goto done;
+ }
+ } else if (input.type) {
goto done;
- if (err == 0)
- break;
- err = -1;
+ } else {
+ return; // no data yet
+ }
int lavc_ret = avcodec_send_frame(s->lavc_actx, frame);
- // On EAGAIN, we're supposed to read remaining output.
- if (lavc_ret == AVERROR(EAGAIN))
- break;
- if (lavc_ret < 0) {
- MP_FATAL(af, "Encode failed.\n");
+ av_frame_free(&frame);
+ if (lavc_ret < 0 && lavc_ret != AVERROR(EAGAIN)) {
+ MP_FATAL(f, "Encode failed (send).\n");
goto done;
}
- s->encoder_buffered += s->input->samples;
- s->input->samples = 0;
- }
- int lavc_ret = avcodec_receive_packet(s->lavc_actx, &pkt);
- if (lavc_ret == AVERROR(EAGAIN)) {
- // Need to buffer more input.
- err = 0;
- goto done;
- }
- if (lavc_ret < 0) {
- MP_FATAL(af, "Encode failed.\n");
- goto done;
}
- MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n",
- pkt.size, s->pending->samples + s->input->samples);
+ if (!s->in_frame)
+ goto done;
- s->encoder_buffered -= AC3_FRAME_SIZE;
+ out = mp_aframe_create();
+ mp_aframe_set_format(out, AF_FORMAT_S_AC3);
+ mp_aframe_set_chmap(out, &(struct mp_chmap)MP_CHMAP_INIT_STEREO);
+ mp_aframe_set_rate(out, 48000);
- struct mp_audio *out =
- mp_audio_pool_get(af->out_pool, af->data, s->out_samples);
- if (!out)
+ if (mp_aframe_pool_allocate(s->out_pool, out, s->out_samples) < 0)
goto done;
- mp_audio_copy_attributes(out, s->pending);
+
+ int sstride = mp_aframe_get_sstride(out);
+
+ mp_aframe_copy_attributes(out, s->in_frame);
int frame_size = pkt.size;
int header_len = 0;
char hdr[8];
- if (s->cfg_add_iec61937_header && pkt.size > 5) {
+ if (s->opts->add_iec61937_header && pkt.size > 5) {
int bsmod = pkt.data[5] & 0x7;
int len = frame_size;
@@ -336,48 +234,69 @@ static int filter_out(struct af_instance *af)
AV_WL16(hdr + 6, len << 3); // number of bits in payload
}
- if (frame_size > out->samples * out->sstride)
+ if (frame_size > s->out_samples * sstride)
abort();
- char *buf = (char *)out->planes[0];
+ uint8_t **planes = mp_aframe_get_data_rw(out);
+ if (!planes)
+ goto done;
+ char *buf = planes[0];
memcpy(buf, hdr, header_len);
memcpy(buf + header_len, pkt.data, pkt.size);
memset(buf + header_len + pkt.size, 0,
frame_size - (header_len + pkt.size));
swap_16((uint16_t *)(buf + header_len), pkt.size / 2);
- out->samples = frame_size / out->sstride;
- af_add_output_frame(af, out);
+ mp_aframe_set_size(out, frame_size / sstride);
+ mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_AUDIO, out));
+ out = NULL;
err = 0;
done:
av_packet_unref(&pkt);
- av_frame_free(&frame);
- update_delay(af);
- return err;
+ talloc_free(out);
+ if (err)
+ mp_filter_internal_mark_failed(f);
}
-static int af_open(struct af_instance* af){
+static const struct mp_filter_info af_lavcac3enc_filter = {
+ .name = "lavcac3enc",
+ .priv_size = sizeof(struct priv),
+ .process = process,
+ .reset = reset,
+ .destroy = destroy,
+};
- af_ac3enc_t *s = af->priv;
- af->control=control;
- af->uninit=uninit;
- af->filter_frame = filter_frame;
- af->filter_out = filter_out;
+static struct mp_filter *af_lavcac3enc_create(struct mp_filter *parent,
+ void *options)
+{
+ struct mp_filter *f = mp_filter_create(parent, &af_lavcac3enc_filter);
+ if (!f) {
+ talloc_free(options);
+ return NULL;
+ }
+
+ mp_filter_add_pin(f, MP_PIN_IN, "in");
+ mp_filter_add_pin(f, MP_PIN_OUT, "out");
- s->lavc_acodec = avcodec_find_encoder_by_name(s->cfg_encoder);
+ struct priv *s = f->priv;
+ s->opts = talloc_steal(s, options);
+ s->cur_format = talloc_steal(s, mp_aframe_create());
+ s->out_pool = mp_aframe_pool_create(s);
+
+ s->lavc_acodec = avcodec_find_encoder_by_name(s->opts->encoder);
if (!s->lavc_acodec) {
- MP_ERR(af, "Couldn't find encoder %s.\n", s->cfg_encoder);
- return AF_ERROR;
+ MP_ERR(f, "Couldn't find encoder %s.\n", s->opts->encoder);
+ goto error;
}
s->lavc_actx = avcodec_alloc_context3(s->lavc_acodec);
if (!s->lavc_actx) {
- MP_ERR(af, "Audio LAVC, couldn't allocate context!\n");
- return AF_ERROR;
+ MP_ERR(f, "Audio LAVC, couldn't allocate context!\n");
+ goto error;
}
- if (mp_set_avopts(af->log, s->lavc_actx, s->cfg_avopts) < 0)
- return AF_ERROR;
+ if (mp_set_avopts(f->log, s->lavc_actx, s->opts->avopts) < 0)
+ goto error;
// For this one, we require the decoder to expert lists of all supported
// parameters. (Not all decoders do that, but the ones we're interested
@@ -385,50 +304,85 @@ static int af_open(struct af_instance* af){
if (!s->lavc_acodec->sample_fmts ||
!s->lavc_acodec->channel_layouts)
{
- MP_ERR(af, "Audio encoder doesn't list supported parameters.\n");
- return AF_ERROR;
+ MP_ERR(f, "Audio encoder doesn't list supported parameters.\n");
+ goto error;
}
- s->input = talloc_zero(s, struct mp_audio);
-
- if (s->cfg_bit_rate) {
+ if (s->opts->bit_rate) {
int i;
for (i = 0; i < 19; i++) {
- if (ac3_bitrate_tab[i] == s->cfg_bit_rate) {
+ if (ac3_bitrate_tab[i] == s->opts->bit_rate) {
s->bit_rate = ac3_bitrate_tab[i] * 1000;
break;
}
}
if (i >= 19) {
- MP_WARN(af, "unable set unsupported bitrate %d, using default "
+ MP_WARN(f, "unable set unsupported bitrate %d, using default "
"bitrate (check manpage to see supported bitrates).\n",
- s->cfg_bit_rate);
+ s->opts->bit_rate);
}
}
- return AF_OK;
-}
+ struct mp_autoconvert *conv = mp_autoconvert_create(f);
+ if (!conv)
+ abort();
-#define OPT_BASE_STRUCT struct af_ac3enc_s
+ const enum AVSampleFormat *lf = s->lavc_acodec->sample_fmts;
+ for (int i = 0; lf && lf[i] != AV_SAMPLE_FMT_NONE; i++) {
+ int mpfmt = af_from_avformat(lf[i]);
+ if (mpfmt)
+ mp_autoconvert_add_afmt(conv, mpfmt);
+ }
-const struct af_info af_info_lavcac3enc = {
- .info = "runtime encode to ac3 using libavcodec",
- .name = "lavcac3enc",
- .open = af_open,
- .priv_size = sizeof(struct af_ac3enc_s),
- .priv_defaults = &(const struct af_ac3enc_s){
- .cfg_add_iec61937_header = 1,
- .cfg_bit_rate = 640,
- .cfg_min_channel_num = 3,
- .cfg_encoder = "ac3",
- },
- .options = (const struct m_option[]) {
- OPT_FLAG("tospdif", cfg_add_iec61937_header, 0),
- OPT_CHOICE_OR_INT("bitrate", cfg_bit_rate, 0, 32, 640,
- ({"auto", 0}, {"default", 0})),
- OPT_INTRANGE("minch", cfg_min_channel_num, 0, 2, 6),
- OPT_STRING("encoder", cfg_encoder, 0),
- OPT_KEYVALUELIST("o", cfg_avopts, 0),
- {0}
+ const uint64_t *lch = s->lavc_acodec->channel_layouts;
+ for (int n = 0; lch && lch[n]; n++) {
+ struct mp_chmap chmap = {0};
+ mp_chmap_from_lavc(&chmap, lch[n]);
+ if (mp_chmap_is_valid(&chmap))
+ mp_autoconvert_add_chmap(conv, &chmap);
+ }
+
+ // At least currently, the AC3 encoder doesn't export sample rates.
+ mp_autoconvert_add_srate(conv, 48000);
+
+ mp_pin_connect(conv->f->pins[0], f->ppins[0]);
+
+ struct mp_filter *fs = mp_fixed_aframe_size_create(f, AC3_FRAME_SIZE, true);
+ if (!fs)
+ abort();
+
+ mp_pin_connect(fs->pins[0], conv->f->pins[1]);
+ s->in_pin = fs->pins[1];
+
+ return f;
+
+error:
+ talloc_free(f);
+ return NULL;
+}
+
+#define OPT_BASE_STRUCT struct f_opts
+
+const struct mp_user_filter_entry af_lavcac3enc = {
+ .desc = {
+ .description = "runtime encode to ac3 using libavcodec",
+ .name = "lavcac3enc",
+ .priv_size = sizeof(OPT_BASE_STRUCT),
+ .priv_defaults = &(const OPT_BASE_STRUCT) {
+ .add_iec61937_header = 1,
+ .bit_rate = 640,
+ .min_channel_num = 3,
+ .encoder = "ac3",
+ },
+ .options = (const struct m_option[]) {
+ OPT_FLAG("tospdif", add_iec61937_header, 0),
+ OPT_CHOICE_OR_INT("bitrate", bit_rate, 0, 32, 640,
+ ({"auto", 0}, {"default", 0})),
+ OPT_INTRANGE("minch", min_channel_num, 0, 2, 6),
+ OPT_STRING("encoder", encoder, 0),
+ OPT_KEYVALUELIST("o", avopts, 0),
+ {0}
+ },
},
+ .create = af_lavcac3enc_create,
};