From cd99146253cf9de5dad5694b97027d5612fdc61d Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 2 Jul 2012 20:13:40 +0200 Subject: [PATCH] lavfi: add error handling to filter_samples(). --- libavfilter/af_amix.c | 22 +++++++++++--------- libavfilter/af_asyncts.c | 38 ++++++++++++++++++++--------------- libavfilter/af_channelmap.c | 10 +++++---- libavfilter/af_channelsplit.c | 15 +++++++++----- libavfilter/af_join.c | 8 +++++--- libavfilter/af_resample.c | 25 +++++++++++++++++------ libavfilter/asink_anullsink.c | 5 ++++- libavfilter/audio.c | 12 +++++------ libavfilter/audio.h | 5 ++++- libavfilter/avfilter.h | 6 +++++- libavfilter/buffersink.c | 8 +++++++- libavfilter/buffersrc.c | 5 +++-- libavfilter/fifo.c | 26 ++++++++++++++++-------- libavfilter/internal.h | 6 +++++- libavfilter/split.c | 14 ++++++++----- 15 files changed, 136 insertions(+), 69 deletions(-) diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index 439231fbd1..d79a626d0a 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -311,9 +311,7 @@ static int output_frame(AVFilterLink *outlink, int nb_samples) if (s->next_pts != AV_NOPTS_VALUE) s->next_pts += nb_samples; - ff_filter_samples(outlink, out_buf); - - return 0; + return ff_filter_samples(outlink, out_buf); } /** @@ -454,31 +452,37 @@ static int request_frame(AVFilterLink *outlink) return output_frame(outlink, available_samples); } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; MixContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - int i; + int i, ret = 0; for (i = 0; i < ctx->nb_inputs; i++) if (ctx->inputs[i] == inlink) break; if (i >= ctx->nb_inputs) { av_log(ctx, AV_LOG_ERROR, "unknown input link\n"); - return; + ret = AVERROR(EINVAL); + goto fail; } if (i == 0) { int64_t pts = av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); - frame_list_add_frame(s->frame_list, buf->audio->nb_samples, pts); + ret = frame_list_add_frame(s->frame_list, buf->audio->nb_samples, pts); + if (ret < 0) + goto fail; } - av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data, - buf->audio->nb_samples); + ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data, + buf->audio->nb_samples); +fail: avfilter_unref_buffer(buf); + + return ret; } static int init(AVFilterContext *ctx, const char *args) diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c index 097bc6045f..4052fbdce7 100644 --- a/libavfilter/af_asyncts.c +++ b/libavfilter/af_asyncts.c @@ -136,18 +136,18 @@ static int request_frame(AVFilterLink *link) avresample_convert(s->avr, (void**)buf->extended_data, buf->linesize[0], nb_samples, NULL, 0, 0); buf->pts = s->pts; - ff_filter_samples(link, buf); - return 0; + return ff_filter_samples(link, buf); } return ret; } -static void write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf) +static int write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf) { - avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, - buf->linesize[0], buf->audio->nb_samples); + int ret = avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, + buf->linesize[0], buf->audio->nb_samples); avfilter_unref_buffer(buf); + return ret; } /* get amount of data currently buffered, in samples */ @@ -156,7 +156,7 @@ static int64_t get_delay(ASyncContext *s) return avresample_available(s->avr) + avresample_get_delay(s->avr); } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; ASyncContext *s = ctx->priv; @@ -164,7 +164,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) int nb_channels = av_get_channel_layout_nb_channels(buf->audio->channel_layout); int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts : av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); - int out_size; + int out_size, ret; int64_t delta; /* buffer data until we get the first timestamp */ @@ -172,14 +172,12 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) if (pts != AV_NOPTS_VALUE) { s->pts = pts - get_delay(s); } - write_to_fifo(s, buf); - return; + return write_to_fifo(s, buf); } /* now wait for the next timestamp */ if (pts == AV_NOPTS_VALUE) { - write_to_fifo(s, buf); - return; + return write_to_fifo(s, buf); } /* when we have two timestamps, compute how many samples would we have @@ -202,8 +200,10 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) if (out_size > 0) { AVFilterBufferRef *buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, out_size); - if (!buf_out) - return; + if (!buf_out) { + ret = AVERROR(ENOMEM); + goto fail; + } avresample_read(s->avr, (void**)buf_out->extended_data, out_size); buf_out->pts = s->pts; @@ -212,7 +212,9 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) av_samples_set_silence(buf_out->extended_data, out_size - delta, delta, nb_channels, buf->format); } - ff_filter_samples(outlink, buf_out); + ret = ff_filter_samples(outlink, buf_out); + if (ret < 0) + goto fail; s->got_output = 1; } else { av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " @@ -223,9 +225,13 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) avresample_read(s->avr, NULL, avresample_available(s->avr)); s->pts = pts - avresample_get_delay(s->avr); - avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, - buf->linesize[0], buf->audio->nb_samples); + ret = avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, + buf->linesize[0], buf->audio->nb_samples); + +fail: avfilter_unref_buffer(buf); + + return ret; } AVFilter avfilter_af_asyncts = { diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 0dfffaa036..1d32d2a087 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -313,7 +313,7 @@ static int channelmap_query_formats(AVFilterContext *ctx) return 0; } -static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; @@ -330,8 +330,10 @@ static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *b if (nch_out > FF_ARRAY_ELEMS(buf->data)) { uint8_t **new_extended_data = av_mallocz(nch_out * sizeof(*buf->extended_data)); - if (!new_extended_data) - return; + if (!new_extended_data) { + avfilter_unref_buffer(buf); + return AVERROR(ENOMEM); + } if (buf->extended_data == buf->data) { buf->extended_data = new_extended_data; } else { @@ -353,7 +355,7 @@ static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *b memcpy(buf->data, buf->extended_data, FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0])); - ff_filter_samples(outlink, buf); + return ff_filter_samples(outlink, buf); } static int channelmap_config_input(AVFilterLink *inlink) diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c index ed134d2885..32b85d82f8 100644 --- a/libavfilter/af_channelsplit.c +++ b/libavfilter/af_channelsplit.c @@ -110,24 +110,29 @@ static int query_formats(AVFilterContext *ctx) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; - int i; + int i, ret = 0; for (i = 0; i < ctx->nb_outputs; i++) { AVFilterBufferRef *buf_out = avfilter_ref_buffer(buf, ~AV_PERM_WRITE); - if (!buf_out) - return; + if (!buf_out) { + ret = AVERROR(ENOMEM); + break; + } buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[i]; buf_out->audio->channel_layout = av_channel_layout_extract_channel(buf->audio->channel_layout, i); - ff_filter_samples(ctx->outputs[i], buf_out); + ret = ff_filter_samples(ctx->outputs[i], buf_out); + if (ret < 0) + break; } avfilter_unref_buffer(buf); + return ret; } AVFilter avfilter_af_channelsplit = { diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index e86c556f5b..9ed11a9991 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -92,7 +92,7 @@ static const AVClass join_class = { .version = LIBAVUTIL_VERSION_INT, }; -static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) { AVFilterContext *ctx = link->dst; JoinContext *s = ctx->priv; @@ -104,6 +104,8 @@ static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) av_assert0(i < ctx->nb_inputs); av_assert0(!s->input_frames[i]); s->input_frames[i] = buf; + + return 0; } static int parse_maps(AVFilterContext *ctx) @@ -468,11 +470,11 @@ static int join_request_frame(AVFilterLink *outlink) priv->nb_in_buffers = ctx->nb_inputs; buf->buf->priv = priv; - ff_filter_samples(outlink, buf); + ret = ff_filter_samples(outlink, buf); memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs); - return 0; + return ret; fail: avfilter_unref_buffer(buf); diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c index 8fbe60b2cf..1360c1ca49 100644 --- a/libavfilter/af_resample.c +++ b/libavfilter/af_resample.c @@ -157,21 +157,21 @@ static int request_frame(AVFilterLink *outlink) } buf->pts = s->next_pts; - ff_filter_samples(outlink, buf); - return 0; + return ff_filter_samples(outlink, buf); } return ret; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; ResampleContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + int ret; if (s->avr) { AVFilterBufferRef *buf_out; - int delay, nb_samples, ret; + int delay, nb_samples; /* maximum possible samples lavr can output */ delay = avresample_get_delay(s->avr); @@ -180,10 +180,19 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) AV_ROUND_UP); buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); + if (!buf_out) { + ret = AVERROR(ENOMEM); + goto fail; + } + ret = avresample_convert(s->avr, (void**)buf_out->extended_data, buf_out->linesize[0], nb_samples, (void**)buf->extended_data, buf->linesize[0], buf->audio->nb_samples); + if (ret < 0) { + avfilter_unref_buffer(buf_out); + goto fail; + } av_assert0(!avresample_available(s->avr)); @@ -209,14 +218,18 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) s->next_pts = buf_out->pts + buf_out->audio->nb_samples; - ff_filter_samples(outlink, buf_out); + ret = ff_filter_samples(outlink, buf_out); s->got_output = 1; } + +fail: avfilter_unref_buffer(buf); } else { - ff_filter_samples(outlink, buf); + ret = ff_filter_samples(outlink, buf); s->got_output = 1; } + + return ret; } AVFilter avfilter_af_resample = { diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c index b527850d4a..74bc43b7f2 100644 --- a/libavfilter/asink_anullsink.c +++ b/libavfilter/asink_anullsink.c @@ -19,7 +19,10 @@ #include "avfilter.h" #include "internal.h" -static void null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) { } +static int null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) +{ + return 0; +} AVFilter avfilter_asink_anullsink = { .name = "anullsink", diff --git a/libavfilter/audio.c b/libavfilter/audio.c index 14896081a3..d518b247a3 100644 --- a/libavfilter/audio.c +++ b/libavfilter/audio.c @@ -146,15 +146,15 @@ fail: return NULL; } -static void default_filter_samples(AVFilterLink *link, - AVFilterBufferRef *samplesref) +static int default_filter_samples(AVFilterLink *link, + AVFilterBufferRef *samplesref) { - ff_filter_samples(link->dst->outputs[0], samplesref); + return ff_filter_samples(link->dst->outputs[0], samplesref); } -void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) +int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) { - void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *); + int (*filter_samples)(AVFilterLink *, AVFilterBufferRef *); AVFilterPad *dst = link->dstpad; AVFilterBufferRef *buf_out; @@ -185,6 +185,6 @@ void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) } else buf_out = samplesref; - filter_samples(link, buf_out); + return filter_samples(link, buf_out); } diff --git a/libavfilter/audio.h b/libavfilter/audio.h index 9af44f8a1c..fa448e2fd6 100644 --- a/libavfilter/audio.h +++ b/libavfilter/audio.h @@ -49,7 +49,10 @@ AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms, * @param samplesref a reference to the buffer of audio samples being sent. The * receiving filter will free this reference when it no longer * needs it or pass it on to the next filter. + * + * @return >= 0 on success, a negative AVERROR on error. The receiving filter + * is responsible for unreferencing samplesref in case of error. */ -void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref); +int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref); #endif /* AVFILTER_AUDIO_H */ diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index aaf86e9c97..10d64ad614 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -288,8 +288,12 @@ struct AVFilterPad { * and should do its processing. * * Input audio pads only. + * + * @return >= 0 on success, a negative AVERROR on error. This function + * must ensure that samplesref is properly unreferenced on error if it + * hasn't been passed on to another filter. */ - void (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); + int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); /** * Frame poll callback. This returns the number of immediately available diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index 50d949b2ac..75b2ee4376 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -56,6 +56,12 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *buf) link->cur_buf = NULL; }; +static int filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) +{ + start_frame(link, buf); + return 0; +} + int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) { BufferSinkContext *s = ctx->priv; @@ -160,7 +166,7 @@ AVFilter avfilter_asink_abuffer = { .inputs = (AVFilterPad[]) {{ .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_samples = start_frame, + .filter_samples = filter_samples, .min_perms = AV_PERM_READ, .needs_fifo = 1 }, { .name = NULL }}, diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index 0b9d5d0829..8df3b615da 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -312,6 +312,7 @@ static int request_frame(AVFilterLink *link) { BufferSourceContext *c = link->src->priv; AVFilterBufferRef *buf; + int ret = 0; if (!av_fifo_size(c->fifo)) { if (c->eof) @@ -327,7 +328,7 @@ static int request_frame(AVFilterLink *link) ff_end_frame(link); break; case AVMEDIA_TYPE_AUDIO: - ff_filter_samples(link, avfilter_ref_buffer(buf, ~0)); + ret = ff_filter_samples(link, avfilter_ref_buffer(buf, ~0)); break; default: return AVERROR(EINVAL); @@ -335,7 +336,7 @@ static int request_frame(AVFilterLink *link) avfilter_unref_buffer(buf); - return 0; + return ret; } static int poll_frame(AVFilterLink *link) diff --git a/libavfilter/fifo.c b/libavfilter/fifo.c index 234df7ffa5..e09e3192ba 100644 --- a/libavfilter/fifo.c +++ b/libavfilter/fifo.c @@ -72,13 +72,25 @@ static av_cold void uninit(AVFilterContext *ctx) avfilter_unref_buffer(fifo->buf_out); } -static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf) { FifoContext *fifo = inlink->dst->priv; fifo->last->next = av_mallocz(sizeof(Buf)); + if (!fifo->last->next) { + avfilter_unref_buffer(buf); + return AVERROR(ENOMEM); + } + fifo->last = fifo->last->next; fifo->last->buf = buf; + + return 0; +} + +static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) +{ + add_to_queue(inlink, buf); } static void queue_pop(FifoContext *s) @@ -210,15 +222,13 @@ static int return_audio_frame(AVFilterContext *ctx) buf_out = s->buf_out; s->buf_out = NULL; } - ff_filter_samples(link, buf_out); - - return 0; + return ff_filter_samples(link, buf_out); } static int request_frame(AVFilterLink *outlink) { FifoContext *fifo = outlink->src->priv; - int ret; + int ret = 0; if (!fifo->root.next) { if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0) @@ -238,7 +248,7 @@ static int request_frame(AVFilterLink *outlink) if (outlink->request_samples) { return return_audio_frame(outlink->src); } else { - ff_filter_samples(outlink, fifo->root.next->buf); + ret = ff_filter_samples(outlink, fifo->root.next->buf); queue_pop(fifo); } break; @@ -246,7 +256,7 @@ static int request_frame(AVFilterLink *outlink) return AVERROR(EINVAL); } - return 0; + return ret; } AVFilter avfilter_vf_fifo = { @@ -261,7 +271,7 @@ AVFilter avfilter_vf_fifo = { .inputs = (AVFilterPad[]) {{ .name = "default", .type = AVMEDIA_TYPE_VIDEO, .get_video_buffer= ff_null_get_video_buffer, - .start_frame = add_to_queue, + .start_frame = start_frame, .draw_slice = draw_slice, .end_frame = end_frame, .rej_perms = AV_PERM_REUSE2, }, diff --git a/libavfilter/internal.h b/libavfilter/internal.h index 954610e3ca..26059c927b 100644 --- a/libavfilter/internal.h +++ b/libavfilter/internal.h @@ -111,8 +111,12 @@ struct AVFilterPad { * and should do its processing. * * Input audio pads only. + * + * @return >= 0 on success, a negative AVERROR on error. This function + * must ensure that samplesref is properly unreferenced on error if it + * hasn't been passed on to another filter. */ - void (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); + int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); /** * Frame poll callback. This returns the number of immediately available diff --git a/libavfilter/split.c b/libavfilter/split.c index ae810e52c6..a3f6ef2337 100644 --- a/libavfilter/split.c +++ b/libavfilter/split.c @@ -110,15 +110,19 @@ AVFilter avfilter_vf_split = { .outputs = (AVFilterPad[]) {{ .name = NULL}}, }; -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) { AVFilterContext *ctx = inlink->dst; - int i; + int i, ret = 0; - for (i = 0; i < ctx->nb_outputs; i++) - ff_filter_samples(inlink->dst->outputs[i], - avfilter_ref_buffer(samplesref, ~AV_PERM_WRITE)); + for (i = 0; i < ctx->nb_outputs; i++) { + ret = ff_filter_samples(inlink->dst->outputs[i], + avfilter_ref_buffer(samplesref, ~AV_PERM_WRITE)); + if (ret < 0) + break; + } avfilter_unref_buffer(samplesref); + return ret; } AVFilter avfilter_af_asplit = {