summaryrefslogtreecommitdiffstats
path: root/audio/filter
diff options
context:
space:
mode:
Diffstat (limited to 'audio/filter')
-rw-r--r--audio/filter/af.c260
-rw-r--r--audio/filter/af.h5
-rw-r--r--audio/filter/af_delay.c194
-rw-r--r--audio/filter/af_format.c16
-rw-r--r--audio/filter/af_lavcac3enc.c46
-rw-r--r--audio/filter/af_lavrresample.c21
-rw-r--r--audio/filter/af_volume.c20
7 files changed, 181 insertions, 381 deletions
diff --git a/audio/filter/af.c b/audio/filter/af.c
index 21b0982692..a132965295 100644
--- a/audio/filter/af.c
+++ b/audio/filter/af.c
@@ -31,7 +31,6 @@
#include "af.h"
// Static list of filters
-extern const struct af_info af_info_delay;
extern const struct af_info af_info_channels;
extern const struct af_info af_info_format;
extern const struct af_info af_info_volume;
@@ -46,7 +45,6 @@ extern const struct af_info af_info_lavfi;
extern const struct af_info af_info_rubberband;
static const struct af_info *const filter_list[] = {
- &af_info_delay,
&af_info_channels,
&af_info_format,
&af_info_volume,
@@ -256,6 +254,8 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
mp_snprintf_cat(b, sizeof(b), "\"%s\" ", af->label);
if (af->data)
mp_snprintf_cat(b, sizeof(b), "%s", mp_audio_config_to_str(af->data));
+ if (af->auto_inserted)
+ mp_snprintf_cat(b, sizeof(b), " [a]");
if (af == at)
mp_snprintf_cat(b, sizeof(b), " <-");
MP_MSG(s, msg_level, "%s\n", b);
@@ -266,164 +266,156 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
MP_MSG(s, msg_level, " [ao] %s\n", mp_audio_config_to_str(&s->output));
}
-// in is what af can take as input - insert a conversion filter if the actual
-// input format doesn't match what af expects.
-// Returns:
-// AF_OK: must call af_reinit() or equivalent, format matches (or is closer)
-// AF_FALSE: nothing was changed, format matches
-// else: error
-static int af_fix_format_conversion(struct af_stream *s,
- struct af_instance **p_af,
- struct mp_audio in)
+static void reset_formats(struct af_stream *s)
{
- int rv;
- struct af_instance *af = *p_af;
- struct af_instance *prev = af->prev;
- struct mp_audio actual = *prev->data;
- if (actual.format == in.format)
- return AF_FALSE;
- int dstfmt = in.format;
- char *filter = "lavrresample";
- if (!af_lavrresample_test_conversion(actual.format, dstfmt))
- return AF_ERROR;
- if (strcmp(filter, prev->info->name) == 0) {
- if (prev->control(prev, AF_CONTROL_SET_FORMAT, &dstfmt) == AF_OK) {
- *p_af = prev;
- return AF_OK;
- }
- return AF_ERROR;
- }
- struct af_instance *new = af_prepend(s, af, filter, NULL);
- if (new == NULL)
- return AF_ERROR;
- new->auto_inserted = true;
- if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_FORMAT, &dstfmt))) {
- af_remove(s, new);
- return rv;
+ struct mp_audio none = {0};
+ for (struct af_instance *af = s->first; af; af = af->next) {
+ if (af != s->first && af != s->last)
+ mp_audio_copy_config(af->data, &none);
}
- *p_af = new;
- return AF_OK;
}
-// same as af_fix_format_conversion - only wrt. channels
-static int af_fix_channels(struct af_stream *s, struct af_instance **p_af,
- struct mp_audio in)
+static int filter_reinit(struct af_instance *af)
{
- int rv;
- struct af_instance *af = *p_af;
struct af_instance *prev = af->prev;
- struct mp_audio actual = *prev->data;
- if (mp_chmap_equals(&actual.channels, &in.channels))
- return AF_FALSE;
- if (prev->control(prev, AF_CONTROL_SET_CHANNELS, &in.channels) == AF_OK) {
- *p_af = prev;
- return AF_OK;
- }
- char *filter = "lavrresample";
- struct af_instance *new = af_prepend(s, af, filter, NULL);
- if (new == NULL)
+ assert(prev);
+
+ // Check if this is the first filter
+ struct mp_audio in = *prev->data;
+ // Reset just in case...
+ mp_audio_set_null_data(&in);
+
+ if (!mp_audio_config_valid(&in))
return AF_ERROR;
- new->auto_inserted = true;
- if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_CHANNELS, &in.channels)))
- return rv;
- *p_af = new;
- return AF_OK;
+
+ af->fmt_in = in;
+ int rv = af->control(af, AF_CONTROL_REINIT, &in);
+ if (rv == AF_OK && !mp_audio_config_equals(&in, prev->data))
+ rv = AF_FALSE; // conversion filter needed
+ if (rv == AF_FALSE)
+ af->fmt_in = in;
+
+ if (rv == AF_OK) {
+ if (!mp_audio_config_valid(af->data))
+ return AF_ERROR;
+ af->fmt_out = *af->data;
+ }
+
+ return rv;
}
-static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
- struct mp_audio in)
+static int filter_reinit_with_conversion(struct af_stream *s, struct af_instance *af)
{
- int rv;
- struct af_instance *af = *p_af;
- struct af_instance *prev = af->prev;
- struct mp_audio actual = *prev->data;
- if (actual.rate == in.rate)
- return AF_FALSE;
- if (prev->control(prev, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate) == AF_OK) {
- *p_af = prev;
- return AF_OK;
+ int rv = filter_reinit(af);
+
+ // Conversion filter is needed
+ if (rv == AF_FALSE) {
+ // First try if we can change the output format of the previous
+ // filter to the input format the current filter is expecting.
+ struct mp_audio in = af->fmt_in;
+ if (af->prev != s->first && !mp_audio_config_equals(af->prev->data, &in)) {
+ // This should have been successful (because it succeeded
+ // before), even if just reverting to the old output format.
+ mp_audio_copy_config(af->prev->data, &in);
+ rv = filter_reinit(af->prev);
+ if (rv != AF_OK)
+ return rv;
+ }
+ if (!mp_audio_config_equals(af->prev->data, &in)) {
+ // Retry with conversion filter added.
+ struct af_instance *new =
+ af_prepend(s, af, "lavrresample", NULL);
+ if (!new)
+ return AF_ERROR;
+ new->auto_inserted = true;
+ mp_audio_copy_config(new->data, &in);
+ rv = filter_reinit(new);
+ if (rv != AF_OK)
+ af_remove(s, new);
+ }
+ if (rv == AF_OK)
+ rv = filter_reinit(af);
}
- char *filter = "lavrresample";
- struct af_instance *new = af_prepend(s, af, filter, NULL);
- if (new == NULL)
- return AF_ERROR;
- new->auto_inserted = true;
- if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate)))
- return rv;
- *p_af = new;
- return AF_OK;
+
+ return rv;
}
-static void reset_formats(struct af_stream *s)
+static int af_find_output_conversion(struct af_stream *s, struct mp_audio *cfg)
{
- for (struct af_instance *af = s->first; af; af = af->next) {
- af->control(af, AF_CONTROL_SET_RESAMPLE_RATE, &(int){0});
- af->control(af, AF_CONTROL_SET_CHANNELS, &(struct mp_chmap){0});
- af->control(af, AF_CONTROL_SET_FORMAT, &(int){0});
+ assert(mp_audio_config_valid(&s->output));
+ assert(s->initialized > 0);
+
+ if (mp_chmap_equals_reordered(&s->input.channels, &s->output.channels))
+ return AF_ERROR;
+
+ // Heuristic to detect point of conversion. If it looks like something
+ // more complicated is going on, better bail out.
+ // We expect that the last filter converts channels.
+ struct af_instance *conv = s->last->prev;
+ if (!conv->auto_inserted)
+ return AF_ERROR;
+ if (!(mp_chmap_equals_reordered(&conv->fmt_in.channels, &s->input.channels) &&
+ mp_chmap_equals_reordered(&conv->fmt_out.channels, &s->output.channels)))
+ return AF_ERROR;
+ // Also, should be the only one which does auto conversion.
+ for (struct af_instance *af = s->first->next; af != s->last; af = af->next)
+ {
+ if (af != conv && af->auto_inserted &&
+ !mp_chmap_equals_reordered(&af->fmt_in.channels, &af->fmt_out.channels))
+ return AF_ERROR;
}
+ // And not if it's the only filter.
+ if (conv->prev == s->first && conv->next == s->last)
+ return AF_ERROR;
+
+ *cfg = s->output;
+ return AF_OK;
}
// Return AF_OK on success or AF_ERROR on failure.
-// Warning:
-// A failed af_reinit() leaves the audio chain behind in a useless, broken
-// state (for example, format filters that were tentatively inserted stay
-// inserted).
-// In that case, you should always rebuild the filter chain, or abort.
-static int af_reinit(struct af_stream *s)
-{
+static int af_do_reinit(struct af_stream *s, bool second_pass)
+{
+ struct mp_audio convert_early = {0};
+ if (second_pass) {
+ // If a channel conversion happens, and it is done by an auto-inserted
+ // filter, then insert a filter to convert it early. Otherwise, do
+ // nothing and return immediately.
+ if (af_find_output_conversion(s, &convert_early) != AF_OK)
+ return AF_OK;
+ }
+
remove_auto_inserted_filters(s);
af_chain_forget_frames(s);
reset_formats(s);
s->first->fmt_in = s->first->fmt_out = s->input;
+
+ if (mp_audio_config_valid(&convert_early)) {
+ struct af_instance *new = af_prepend(s, s->first, "lavrresample", NULL);
+ if (!new)
+ return AF_ERROR;
+ new->auto_inserted = true;
+ mp_audio_copy_config(new->data, &convert_early);
+ int rv = filter_reinit(new);
+ if (rv != AF_DETACH && rv != AF_OK)
+ return AF_ERROR;
+ MP_VERBOSE(s, "Moving up output conversion.\n");
+ }
+
// Start with the second filter, as the first filter is the special input
// filter which needs no initialization.
struct af_instance *af = s->first->next;
- // Up to 4 retries per filter (channel, rate, format conversions)
- int max_retry = 4;
- int retry = 0;
while (af) {
- if (retry >= max_retry)
- goto negotiate_error;
-
- // Check if this is the first filter
- struct mp_audio in = *af->prev->data;
- // Reset just in case...
- mp_audio_set_null_data(&in);
-
- if (!mp_audio_config_valid(&in))
- goto error;
+ int rv = filter_reinit_with_conversion(s, af);
- af->fmt_in = in;
- int rv = af->control(af, AF_CONTROL_REINIT, &in);
- if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data))
- rv = AF_FALSE; // conversion filter needed
switch (rv) {
case AF_OK:
- if (!mp_audio_config_valid(af->data))
- goto error;
- af->fmt_out = *af->data;
af = af->next;
break;
- case AF_FALSE: { // Configuration filter is needed
- if (af_fix_channels(s, &af, in) == AF_OK) {
- retry++;
- continue;
- }
- if (af_fix_rate(s, &af, in) == AF_OK) {
- retry++;
- continue;
- }
- // Do this last, to prevent "format->lavrresample" being added to
- // the filter chain when output formats not supported by
- // af_lavrresample are in use.
- if (af_fix_format_conversion(s, &af, in) == AF_OK) {
- retry++;
- continue;
- }
+ case AF_FALSE: {
// If the format conversion is (probably) caused by spdif, then
// (as a feature) drop the filter, instead of failing hard.
int fmt_in1 = af->prev->data->format;
- int fmt_in2 = in.format;
+ int fmt_in2 = af->fmt_in.format;
if (af_fmt_is_valid(fmt_in1) && af_fmt_is_valid(fmt_in2)) {
bool spd1 = af_fmt_is_spdif(fmt_in1);
bool spd2 = af_fmt_is_spdif(fmt_in2);
@@ -434,7 +426,6 @@ static int af_reinit(struct af_stream *s)
struct af_instance *aft = af->prev;
af_remove(s, af);
af = aft->next;
- retry++;
continue;
}
}
@@ -452,8 +443,6 @@ static int af_reinit(struct af_stream *s)
af->info->name, rv);
goto error;
}
- if (af && !af->auto_inserted)
- retry = 0;
}
/* Set previously unset fields in s->output to those of the filter chain
@@ -477,6 +466,19 @@ error:
return AF_ERROR;
}
+static int af_reinit(struct af_stream *s)
+{
+ int r = af_do_reinit(s, false);
+ if (r == AF_OK && mp_audio_config_valid(&s->output)) {
+ r = af_do_reinit(s, true);
+ if (r != AF_OK) {
+ MP_ERR(s, "Failed second pass filter negotiation.\n");
+ r = af_do_reinit(s, false);
+ }
+ }
+ return r;
+}
+
// Uninit and remove all filters
void af_uninit(struct af_stream *s)
{
diff --git a/audio/filter/af.h b/audio/filter/af.h
index 9c49081f66..697024b781 100644
--- a/audio/filter/af.h
+++ b/audio/filter/af.h
@@ -112,9 +112,6 @@ struct af_stream {
enum af_control {
AF_CONTROL_REINIT = 1,
AF_CONTROL_RESET,
- AF_CONTROL_SET_RESAMPLE_RATE,
- AF_CONTROL_SET_FORMAT,
- AF_CONTROL_SET_CHANNELS,
AF_CONTROL_SET_VOLUME,
AF_CONTROL_GET_VOLUME,
AF_CONTROL_SET_PAN_LEVEL,
@@ -160,6 +157,4 @@ int af_test_output(struct af_instance *af, struct mp_audio *out);
int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma);
float af_softclip(float a);
-bool af_lavrresample_test_conversion(int src_format, int dst_format);
-
#endif /* MPLAYER_AF_H */
diff --git a/audio/filter/af_delay.c b/audio/filter/af_delay.c
deleted file mode 100644
index 8d1cca8a72..0000000000
--- a/audio/filter/af_delay.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * This audio filter delays the output signal for the different
- * channels and can be used for simple position panning.
- * An extension for this filter would be a reverb.
- *
- * Original author: Anders
- *
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * mpv is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "common/common.h"
-#include "af.h"
-
-#define L 65536
-
-#define UPDATEQI(qi) qi=(qi+1)&(L-1)
-
-// Data for specific instances of this filter
-typedef struct af_delay_s
-{
- void* q[AF_NCH]; // Circular queues used for delaying audio signal
- int wi[AF_NCH]; // Write index
- int ri; // Read index
- float d[AF_NCH]; // Delay [ms]
- char *delaystr;
-}af_delay_t;
-
-// Initialization and runtime control
-static int control(struct af_instance* af, int cmd, void* arg)
-{
- af_delay_t* s = af->priv;
- switch(cmd){
- case AF_CONTROL_REINIT:{
- int i;
- struct mp_audio *in = arg;
-
- if (in->bps != 1 && in->bps != 2 && in->bps != 4) {
- MP_FATAL(af, "Sample format not supported\n");
- return AF_ERROR;
- }
-
- // Free prevous delay queues
- for(i=0;i<af->data->nch;i++)
- free(s->q[i]);
-
- mp_audio_force_interleaved_format(in);
- mp_audio_copy_config(af->data, in);
-
- // Allocate new delay queues
- for(i=0;i<af->data->nch;i++){
- s->q[i] = calloc(L,af->data->bps);
- if(NULL == s->q[i])
- MP_FATAL(af, "Out of memory\n");
- }
-
- if(AF_OK != af_from_ms(AF_NCH, s->d, s->wi, af->data->rate, 0.0, 1000.0))
- return AF_ERROR;
- s->ri = 0;
- for(i=0;i<AF_NCH;i++){
- MP_DBG(af, "Channel %i delayed by %0.3fms\n",
- i,MPCLAMP(s->d[i],0.0,1000.0));
- MP_TRACE(af, "Channel %i delayed by %i samples\n",
- i,s->wi[i]);
- }
- return AF_OK;
- }
- }
- return AF_UNKNOWN;
-}
-
-// Deallocate memory
-static void uninit(struct af_instance* af)
-{
- int i;
-
- for(i=0;i<AF_NCH;i++)
- free(((af_delay_t*)(af->priv))->q[i]);
-}
-
-static int filter_frame(struct af_instance *af, struct mp_audio *c)
-{
- if (!c)
- return 0;
- af_delay_t* s = af->priv; // Setup for this instance
- int nch = c->nch; // Number of channels
- int len = mp_audio_psize(c)/c->bps; // Number of sample in data chunk
- int ri = 0;
- int ch,i;
- if (af_make_writeable(af, c) < 0) {
- talloc_free(c);
- return -1;
- }
- for(ch=0;ch<nch;ch++){
- switch(c->bps){
- case 1:{
- int8_t* a = c->planes[0];
- int8_t* q = s->q[ch];
- int wi = s->wi[ch];
- ri = s->ri;
- for(i=ch;i<len;i+=nch){
- q[wi] = a[i];
- a[i] = q[ri];
- UPDATEQI(wi);
- UPDATEQI(ri);
- }
- s->wi[ch] = wi;
- break;
- }
- case 2:{
- int16_t* a = c->planes[0];
- int16_t* q = s->q[ch];
- int wi = s->wi[ch];
- ri = s->ri;
- for(i=ch;i<len;i+=nch){
- q[wi] = a[i];
- a[i] = q[ri];
- UPDATEQI(wi);
- UPDATEQI(ri);
- }
- s->wi[ch] = wi;
- break;
- }
- case 4:{
- int32_t* a = c->planes[0];
- int32_t* q = s->q[ch];
- int wi = s->wi[ch];
- ri = s->ri;
- for(i=ch;i<len;i+=nch){
- q[wi] = a[i];
- a[i] = q[ri];
- UPDATEQI(wi);
- UPDATEQI(ri);
- }
- s->wi[ch] = wi;
- break;
- }
- }
- }
- s->ri = ri;
- af_add_output_frame(af, c);
- return 0;
-}
-
-// Allocate memory and set function pointers
-static int af_open(struct af_instance* af){
- af->control=control;
- af->uninit=uninit;
- af->filter_frame = filter_frame;
- af_delay_t *s = af->priv;
- int n = 1;
- int i = 0;
- char* cl = s->delaystr;
- while(cl && n && i < AF_NCH ){
- sscanf(cl,"%f%n",&s->d[i],&n);
- if(n==0 || cl[n-1] == '\0')
- break;
- cl=&cl[n];
- if (*cl != ',')
- break;
- cl++;
- i++;
- }
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT af_delay_t
-const struct af_info af_info_delay = {
- .info = "Delay audio filter",
- .name = "delay",
- .open = af_open,
- .priv_size = sizeof(af_delay_t),
- .options = (const struct m_option[]) {
- OPT_STRING("delays", delaystr, 0),
- {0}
- },
-};
diff --git a/audio/filter/af_format.c b/audio/filter/af_format.c
index c0fe354a39..748c5cbd52 100644
--- a/audio/filter/af_format.c
+++ b/audio/filter/af_format.c
@@ -29,10 +29,10 @@ struct priv {
int in_format;
int in_srate;
- struct mp_chmap in_channels;
+ struct m_channels in_channels;
int out_format;
int out_srate;
- struct mp_chmap out_channels;
+ struct m_channels out_channels;
int fail;
};
@@ -44,8 +44,8 @@ static void force_in_params(struct af_instance *af, struct mp_audio *in)
if (priv->in_format != AF_FORMAT_UNKNOWN)
mp_audio_set_format(in, priv->in_format);
- if (priv->in_channels.num)
- mp_audio_set_channels(in, &priv->in_channels);
+ if (priv->in_channels.num_chmaps > 0)
+ mp_audio_set_channels(in, &priv->in_channels.chmaps[0]);
if (priv->in_srate)
in->rate = priv->in_srate;
@@ -58,8 +58,8 @@ static void force_out_params(struct af_instance *af, struct mp_audio *out)
if (priv->out_format != AF_FORMAT_UNKNOWN)
mp_audio_set_format(out, priv->out_format);
- if (priv->out_channels.num)
- mp_audio_set_channels(out, &priv->out_channels);
+ if (priv->out_channels.num_chmaps > 0)
+ mp_audio_set_channels(out, &priv->out_channels.chmaps[0]);
if (priv->out_srate)
out->rate = priv->out_srate;
@@ -124,10 +124,10 @@ const struct af_info af_info_format = {
.options = (const struct m_option[]) {
OPT_AUDIOFORMAT("format", in_format, 0),
OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000),
- OPT_CHMAP("channels", in_channels, CONF_MIN, .min = 0),
+ OPT_CHANNELS("channels", in_channels, 0, .min = 1),
OPT_AUDIOFORMAT("out-format", out_format, 0),
OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000),
- OPT_CHMAP("out-channels", out_channels, CONF_MIN, .min = 0),
+ OPT_CHANNELS("out-channels", out_channels, 0, .min = 1),
OPT_FLAG("fail", fail, 0),
{0}
},
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
index 26c9cbff58..0a7c5d4440 100644
--- a/audio/filter/af_lavcac3enc.c
+++ b/audio/filter/af_lavcac3enc.c
@@ -33,6 +33,7 @@
#include "config.h"
+#include "common/av_common.h"
#include "common/common.h"
#include "af.h"
#include "audio/audio_buffer.h"
@@ -57,11 +58,13 @@ typedef struct af_ac3enc_s {
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
@@ -168,6 +171,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
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;
}
case AF_CONTROL_RESET:
@@ -176,6 +180,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
talloc_free(s->pending);
s->pending = NULL;
s->input->samples = 0;
+ s->encoder_buffered = 0;
return AF_OK;
}
return AF_UNKNOWN;
@@ -198,8 +203,8 @@ static void uninit(struct af_instance* af)
static void update_delay(struct af_instance *af)
{
af_ac3enc_t *s = af->priv;
- af->delay = ((s->pending ? s->pending->samples : 0) + s->input->samples) /
- (double)s->input->rate;
+ af->delay = ((s->pending ? s->pending->samples : 0) + s->input->samples +
+ s->encoder_buffered) / (double)s->input->rate;
}
static int filter_frame(struct af_instance *af, struct mp_audio *audio)
@@ -232,6 +237,9 @@ static bool fill_buffer(struct af_instance *af)
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);
@@ -249,17 +257,8 @@ static int read_input_frame(struct af_instance *af, AVFrame *frame)
if (!fill_buffer(af))
return 0; // need more input
- frame->nb_samples = s->in_samples;
- frame->format = s->lavc_actx->sample_fmt;
- frame->channel_layout = s->lavc_actx->channel_layout;
-#if LIBAVUTIL_VERSION_MICRO >= 100
- frame->channels = s->lavc_actx->channels;
-#endif
- assert(s->input->num_planes <= AV_NUM_DATA_POINTERS);
- frame->extended_data = frame->data;
- for (int n = 0; n < s->input->num_planes; n++)
- frame->data[n] = s->input->planes[n];
- frame->linesize[0] = s->input->samples * s->input->sstride;
+ if (mp_audio_to_avframe(s->input, frame) < 0)
+ return -1;
return 1;
}
@@ -268,6 +267,9 @@ 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");
@@ -295,6 +297,7 @@ static int filter_out(struct af_instance *af)
MP_FATAL(af, "Encode failed.\n");
goto done;
}
+ s->encoder_buffered += s->input->samples;
s->input->samples = 0;
}
int lavc_ret = avcodec_receive_packet(s->lavc_actx, &pkt);
@@ -303,6 +306,10 @@ static int filter_out(struct af_instance *af)
err = 0;
goto done;
}
+ if (lavc_ret < 0) {
+ MP_FATAL(af, "Encode failed.\n");
+ goto done;
+ }
#else
err = read_input_frame(af, frame);
if (err < 0)
@@ -312,7 +319,6 @@ static int filter_out(struct af_instance *af)
err = -1;
int ok;
int lavc_ret = avcodec_encode_audio2(s->lavc_actx, &pkt, frame, &ok);
- av_frame_free(&frame);
s->input->samples = 0;
if (lavc_ret < 0 || !ok) {
MP_FATAL(af, "Encode failed.\n");
@@ -321,7 +327,9 @@ static int filter_out(struct af_instance *af)
#endif
MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n",
- pkt.size, s->pending->samples);
+ pkt.size, s->pending->samples + s->input->samples);
+
+ s->encoder_buffered -= AC3_FRAME_SIZE;
struct mp_audio *out =
mp_audio_pool_get(af->out_pool, af->data, s->out_samples);
@@ -358,11 +366,12 @@ static int filter_out(struct af_instance *af)
swap_16((uint16_t *)(buf + header_len), pkt.size / 2);
out->samples = frame_size / out->sstride;
af_add_output_frame(af, out);
- update_delay(af);
err = 0;
done:
av_packet_unref(&pkt);
+ av_frame_free(&frame);
+ update_delay(af);
return err;
}
@@ -385,6 +394,10 @@ static int af_open(struct af_instance* af){
MP_ERR(af, "Audio LAVC, couldn't allocate context!\n");
return AF_ERROR;
}
+
+ if (mp_set_avopts(af->log, s->lavc_actx, s->cfg_avopts) < 0)
+ return AF_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
// in do.)
@@ -434,6 +447,7 @@ const struct af_info af_info_lavcac3enc = {
({"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}
},
};
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
index 6fbb445563..fdef69a16b 100644
--- a/audio/filter/af_lavrresample.c
+++ b/audio/filter/af_lavrresample.c
@@ -173,12 +173,6 @@ static int check_output_conversion(int mp_format)
return af_to_avformat(mp_format);
}
-bool af_lavrresample_test_conversion(int src_format, int dst_format)
-{
- return af_to_avformat(src_format) != AV_SAMPLE_FMT_NONE &&
- check_output_conversion(dst_format) != AV_SAMPLE_FMT_NONE;
-}
-
static struct mp_chmap fudge_pairs[][2] = {
{MP_CHMAP2(BL, BR), MP_CHMAP2(SL, SR)},
{MP_CHMAP2(SL, SR), MP_CHMAP2(BL, BR)},
@@ -407,21 +401,6 @@ static int control(struct af_instance *af, int cmd, void *arg)
r = configure_lavrr(af, in, out, true);
return r;
}
- case AF_CONTROL_SET_FORMAT: {
- int format = *(int *)arg;
- if (format && check_output_conversion(format) == AV_SAMPLE_FMT_NONE)
- return AF_FALSE;
-
- mp_audio_set_format(af->data, format);
- return AF_OK;
- }
- case AF_CONTROL_SET_CHANNELS: {
- mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
- return AF_OK;
- }
- case AF_CONTROL_SET_RESAMPLE_RATE:
- af->data->rate = *(int *)arg;
- return AF_OK;
case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: {
s->playback_speed = *(double *)arg;
return AF_OK;
diff --git a/audio/filter/af_volume.c b/audio/filter/af_volume.c
index 7bd7edd66d..e1d5d45e89 100644
--- a/audio/filter/af_volume.c
+++ b/audio/filter/af_volume.c
@@ -71,15 +71,19 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (af_fmt_is_planar(in->format))
mp_audio_set_format(af->data, af_fmt_to_planar(af->data->format));
s->rgain = 1.0;
- if ((s->rgain_track || s->rgain_album) && af->replaygain_data) {
- float gain, peak;
+ struct replaygain_data *rg = af->replaygain_data;
+ if ((s->rgain_track || s->rgain_album) && rg) {
+ MP_VERBOSE(af, "Replaygain: Track=%f/%f Album=%f/%f\n",
+ rg->track_gain, rg->track_peak,
+ rg->album_gain, rg->album_peak);
+ float gain, peak;
if (s->rgain_track) {
- gain = af->replaygain_data->track_gain;
- peak = af->replaygain_data->track_peak;
+ gain = rg->track_gain;
+ peak = rg->track_peak;
} else {
- gain = af->replaygain_data->album_gain;
- peak = af->replaygain_data->album_peak;
+ gain = rg->album_gain;
+ peak = rg->album_peak;
}
gain += s->rgain_preamp;
@@ -115,7 +119,7 @@ static void filter_plane(struct af_instance *af, struct mp_audio *data, int p)
{
struct priv *s = af->priv;
- float level = s->level * s->rgain;
+ float level = s->level * s->rgain * from_dB(s->cfg_volume, 20.0, -200.0, 60.0);
int num_samples = data->samples * data->spf;
if (af_fmt_from_planar(af->data->format) == AF_FORMAT_S16) {
@@ -158,7 +162,7 @@ static int af_open(struct af_instance *af)
struct priv *s = af->priv;
af->control = control;
af->filter_frame = filter;
- s->level = from_dB(s->cfg_volume, 20.0, -200.0, 60.0);
+ s->level = 1.0;
return AF_OK;
}