avfilter/af_speechnorm: fix possible memleak on error to make frame writable

Fix this by adding support for non-writable frames.
This commit is contained in:
Paul B Mahol 2021-10-05 14:45:43 +02:00
parent 2ee4077248
commit 3fe49b51fc

View File

@ -84,7 +84,7 @@ typedef struct SpeechNormalizerContext {
void (*analyze_channel)(AVFilterContext *ctx, ChannelContext *cc, void (*analyze_channel)(AVFilterContext *ctx, ChannelContext *cc,
const uint8_t *srcp, int nb_samples); const uint8_t *srcp, int nb_samples);
void (*filter_channels[2])(AVFilterContext *ctx, void (*filter_channels[2])(AVFilterContext *ctx,
AVFrame *in, int nb_samples); AVFrame *in, AVFrame *out, int nb_samples);
} SpeechNormalizerContext; } SpeechNormalizerContext;
#define OFFSET(x) offsetof(SpeechNormalizerContext, x) #define OFFSET(x) offsetof(SpeechNormalizerContext, x)
@ -295,14 +295,15 @@ ANALYZE_CHANNEL(flt, float, 0.f, (float)MIN_PEAK)
#define FILTER_CHANNELS(name, ptype) \ #define FILTER_CHANNELS(name, ptype) \
static void filter_channels_## name (AVFilterContext *ctx, \ static void filter_channels_## name (AVFilterContext *ctx, \
AVFrame *in, int nb_samples) \ AVFrame *in, AVFrame *out, int nb_samples) \
{ \ { \
SpeechNormalizerContext *s = ctx->priv; \ SpeechNormalizerContext *s = ctx->priv; \
AVFilterLink *inlink = ctx->inputs[0]; \ AVFilterLink *inlink = ctx->inputs[0]; \
\ \
for (int ch = 0; ch < inlink->channels; ch++) { \ for (int ch = 0; ch < inlink->channels; ch++) { \
ChannelContext *cc = &s->cc[ch]; \ ChannelContext *cc = &s->cc[ch]; \
ptype *dst = (ptype *)in->extended_data[ch]; \ const ptype *src = (const ptype *)in->extended_data[ch]; \
ptype *dst = (ptype *)out->extended_data[ch]; \
const int bypass = !(av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels); \ const int bypass = !(av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels); \
int n = 0; \ int n = 0; \
\ \
@ -316,7 +317,7 @@ static void filter_channels_## name (AVFilterContext *ctx,
gain = cc->gain_state; \ gain = cc->gain_state; \
consume_pi(cc, size); \ consume_pi(cc, size); \
for (int i = n; !ctx->is_disabled && i < n + size; i++) \ for (int i = n; !ctx->is_disabled && i < n + size; i++) \
dst[i] *= gain; \ dst[i] = src[i] * gain; \
n += size; \ n += size; \
} \ } \
} \ } \
@ -337,7 +338,8 @@ static float flerp(float min, float max, float mix)
#define FILTER_LINK_CHANNELS(name, ptype, tlerp) \ #define FILTER_LINK_CHANNELS(name, ptype, tlerp) \
static void filter_link_channels_## name (AVFilterContext *ctx, \ static void filter_link_channels_## name (AVFilterContext *ctx, \
AVFrame *in, int nb_samples) \ AVFrame *in, AVFrame *out, \
int nb_samples) \
{ \ { \
SpeechNormalizerContext *s = ctx->priv; \ SpeechNormalizerContext *s = ctx->priv; \
AVFilterLink *inlink = ctx->inputs[0]; \ AVFilterLink *inlink = ctx->inputs[0]; \
@ -369,7 +371,8 @@ static void filter_link_channels_## name (AVFilterContext *ctx,
\ \
for (int ch = 0; ch < inlink->channels; ch++) { \ for (int ch = 0; ch < inlink->channels; ch++) { \
ChannelContext *cc = &s->cc[ch]; \ ChannelContext *cc = &s->cc[ch]; \
ptype *dst = (ptype *)in->extended_data[ch]; \ const ptype *src = (const ptype *)in->extended_data[ch]; \
ptype *dst = (ptype *)out->extended_data[ch]; \
\ \
consume_pi(cc, min_size); \ consume_pi(cc, min_size); \
if (cc->bypass) \ if (cc->bypass) \
@ -377,7 +380,7 @@ static void filter_link_channels_## name (AVFilterContext *ctx,
\ \
for (int i = n; !ctx->is_disabled && i < n + min_size; i++) { \ for (int i = n; !ctx->is_disabled && i < n + min_size; i++) { \
ptype g = tlerp(s->prev_gain, gain, (i - n) / (ptype)min_size); \ ptype g = tlerp(s->prev_gain, gain, (i - n) / (ptype)min_size); \
dst[i] *= g; \ dst[i] = src[i] * g; \
} \ } \
} \ } \
\ \
@ -398,7 +401,7 @@ static int filter_frame(AVFilterContext *ctx)
while (s->queue.available > 0) { while (s->queue.available > 0) {
int min_pi_nb_samples; int min_pi_nb_samples;
AVFrame *in; AVFrame *in, *out;
in = ff_bufqueue_peek(&s->queue, 0); in = ff_bufqueue_peek(&s->queue, 0);
if (!in) if (!in)
@ -410,16 +413,25 @@ static int filter_frame(AVFilterContext *ctx)
in = ff_bufqueue_get(&s->queue); in = ff_bufqueue_get(&s->queue);
ret = av_frame_make_writable(in); if (av_frame_is_writable(in)) {
if (ret < 0) out = in;
return ret; } else {
out = ff_get_audio_buffer(outlink, in->nb_samples);
if (!out) {
av_frame_free(&in);
return AVERROR(ENOMEM);
}
av_frame_copy_props(out, in);
}
s->filter_channels[s->link](ctx, in, in->nb_samples); s->filter_channels[s->link](ctx, in, out, in->nb_samples);
s->pts = in->pts + av_rescale_q(in->nb_samples, av_make_q(1, outlink->sample_rate), s->pts = in->pts + av_rescale_q(in->nb_samples, av_make_q(1, outlink->sample_rate),
outlink->time_base); outlink->time_base);
return ff_filter_frame(outlink, in); if (out != in)
av_frame_free(&in);
return ff_filter_frame(outlink, out);
} }
for (int f = 0; f < ff_inlink_queued_frames(inlink); f++) { for (int f = 0; f < ff_inlink_queued_frames(inlink); f++) {