avfilter/showpalette: fix leak in case of error
[ffmpeg.git] / libavfilter / avfilter.c
index 59fc0fa..1b5cc2f 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/atomic.h"
 #include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/eval.h"
 #include "libavutil/imgutils.h"
+#include "libavutil/internal.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/rational.h"
@@ -34,7 +36,9 @@
 #include "avfilter.h"
 #include "formats.h"
 #include "internal.h"
-#include "audio.h"
+
+#include "libavutil/ffversion.h"
+const char av_filter_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
 
 static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame);
 
@@ -92,16 +96,25 @@ void ff_command_queue_pop(AVFilterContext *filter)
     av_free(c);
 }
 
-void ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
+int ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
                    AVFilterPad **pads, AVFilterLink ***links,
                    AVFilterPad *newpad)
 {
+    AVFilterLink **newlinks;
+    AVFilterPad *newpads;
     unsigned i;
 
     idx = FFMIN(idx, *count);
 
-    *pads  = av_realloc(*pads,  sizeof(AVFilterPad)   * (*count + 1));
-    *links = av_realloc(*links, sizeof(AVFilterLink*) * (*count + 1));
+    newpads  = av_realloc_array(*pads,  *count + 1, sizeof(AVFilterPad));
+    newlinks = av_realloc_array(*links, *count + 1, sizeof(AVFilterLink*));
+    if (newpads)
+        *pads  = newpads;
+    if (newlinks)
+        *links = newlinks;
+    if (!newpads || !newlinks)
+        return AVERROR(ENOMEM);
+
     memmove(*pads  + idx + 1, *pads  + idx, sizeof(AVFilterPad)   * (*count - idx));
     memmove(*links + idx + 1, *links + idx, sizeof(AVFilterLink*) * (*count - idx));
     memcpy(*pads + idx, newpad, sizeof(AVFilterPad));
@@ -109,8 +122,10 @@ void ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
 
     (*count)++;
     for (i = idx + 1; i < *count; i++)
-        if (*links[i])
-            (*(unsigned *)((uint8_t *) *links[i] + padidx_off))++;
+        if ((*links)[i])
+            (*(unsigned *)((uint8_t *) (*links)[i] + padidx_off))++;
+
+    return 0;
 }
 
 int avfilter_link(AVFilterContext *src, unsigned srcpad,
@@ -215,6 +230,11 @@ int avfilter_config_links(AVFilterContext *filter)
         AVFilterLink *inlink;
 
         if (!link) continue;
+        if (!link->src || !link->dst) {
+            av_log(filter, AV_LOG_ERROR,
+                   "Not all input and output are properly linked (%d).\n", i);
+            return AVERROR(EINVAL);
+        }
 
         inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL;
         link->current_pts = AV_NOPTS_VALUE;
@@ -283,7 +303,7 @@ int avfilter_config_links(AVFilterContext *filter)
 
             if ((config_link = link->dstpad->config_props))
                 if ((ret = config_link(link)) < 0) {
-                    av_log(link->src, AV_LOG_ERROR,
+                    av_log(link->dst, AV_LOG_ERROR,
                            "Failed to configure input pad on %s\n",
                            link->dst->name);
                     return ret;
@@ -369,8 +389,23 @@ int ff_poll_frame(AVFilterLink *link)
     return min;
 }
 
-static const char *const var_names[] = {   "t",   "n",   "pos",        NULL };
-enum                                   { VAR_T, VAR_N, VAR_POS, VAR_VARS_NB };
+static const char *const var_names[] = {
+    "t",
+    "n",
+    "pos",
+    "w",
+    "h",
+    NULL
+};
+
+enum {
+    VAR_T,
+    VAR_N,
+    VAR_POS,
+    VAR_W,
+    VAR_H,
+    VAR_VARS_NB
+};
 
 static int set_enable_expr(AVFilterContext *ctx, const char *expr)
 {
@@ -425,7 +460,15 @@ void ff_update_link_current_pts(AVFilterLink *link, int64_t pts)
 int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags)
 {
     if(!strcmp(cmd, "ping")){
+        char local_res[256] = {0};
+
+        if (!res) {
+            res = local_res;
+            res_len = sizeof(local_res);
+        }
         av_strlcatf(res, res_len, "pong from:%s %s\n", filter->filter->name, filter->name);
+        if (res == local_res)
+            av_log(filter, AV_LOG_INFO, "%s", res);
         return 0;
     }else if(!strcmp(cmd, "enable")) {
         return set_enable_expr(filter, arg);
@@ -436,7 +479,11 @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const cha
 }
 
 static AVFilter *first_filter;
+static AVFilter **last_filter = &first_filter;
 
+#if !FF_API_NOCONST_GET_NAME
+const
+#endif
 AVFilter *avfilter_get_by_name(const char *name)
 {
     const AVFilter *f = NULL;
@@ -453,7 +500,7 @@ AVFilter *avfilter_get_by_name(const char *name)
 
 int avfilter_register(AVFilter *filter)
 {
-    AVFilter **f = &first_filter;
+    AVFilter **f = last_filter;
     int i;
 
     /* the filter must select generic or internal exclusively */
@@ -465,11 +512,12 @@ int avfilter_register(AVFilter *filter)
                     || (!input->start_frame && !input->end_frame));
     }
 
-    while (*f)
-        f = &(*f)->next;
-    *f = filter;
     filter->next = NULL;
 
+    while(*f || avpriv_atomic_ptr_cas((void * volatile *)f, NULL, filter))
+        f = &(*f)->next;
+    last_filter = &filter->next;
+
     return 0;
 }
 
@@ -538,9 +586,12 @@ static const AVClass *filter_child_class_next(const AVClass *prev)
 
 #define OFFSET(x) offsetof(AVFilterContext, x)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM
-static const AVOption filters_common_options[] = {
+static const AVOption avfilter_options[] = {
+    { "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS,
+        { .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, FLAGS, "thread_type" },
+        { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .unit = "thread_type" },
     { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
-    { NULL }
+    { NULL },
 };
 
 static const AVClass avfilter_class = {
@@ -549,10 +600,23 @@ static const AVClass avfilter_class = {
     .version    = LIBAVUTIL_VERSION_INT,
     .category   = AV_CLASS_CATEGORY_FILTER,
     .child_next = filter_child_next,
-    .option     = filters_common_options,
     .child_class_next = filter_child_class_next,
+    .option           = avfilter_options,
 };
 
+static int default_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg,
+                           int *ret, int nb_jobs)
+{
+    int i;
+
+    for (i = 0; i < nb_jobs; i++) {
+        int r = func(ctx, arg, i, nb_jobs);
+        if (ret)
+            ret[i] = r;
+    }
+    return 0;
+}
+
 AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name)
 {
     AVFilterContext *ret;
@@ -573,35 +637,43 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name)
             goto err;
     }
 
+    av_opt_set_defaults(ret);
     if (filter->priv_class) {
         *(const AVClass**)ret->priv = filter->priv_class;
         av_opt_set_defaults(ret->priv);
     }
 
+    ret->internal = av_mallocz(sizeof(*ret->internal));
+    if (!ret->internal)
+        goto err;
+    ret->internal->execute = default_execute;
+
     ret->nb_inputs = avfilter_pad_count(filter->inputs);
     if (ret->nb_inputs ) {
-        ret->input_pads   = av_malloc(sizeof(AVFilterPad) * ret->nb_inputs);
+        ret->input_pads   = av_malloc_array(ret->nb_inputs, sizeof(AVFilterPad));
         if (!ret->input_pads)
             goto err;
         memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->nb_inputs);
-        ret->inputs       = av_mallocz(sizeof(AVFilterLink*) * ret->nb_inputs);
+        ret->inputs       = av_mallocz_array(ret->nb_inputs, sizeof(AVFilterLink*));
         if (!ret->inputs)
             goto err;
     }
 
     ret->nb_outputs = avfilter_pad_count(filter->outputs);
     if (ret->nb_outputs) {
-        ret->output_pads  = av_malloc(sizeof(AVFilterPad) * ret->nb_outputs);
+        ret->output_pads  = av_malloc_array(ret->nb_outputs, sizeof(AVFilterPad));
         if (!ret->output_pads)
             goto err;
         memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->nb_outputs);
-        ret->outputs      = av_mallocz(sizeof(AVFilterLink*) * ret->nb_outputs);
+        ret->outputs      = av_mallocz_array(ret->nb_outputs, sizeof(AVFilterLink*));
         if (!ret->outputs)
             goto err;
     }
 #if FF_API_FOO_COUNT
+FF_DISABLE_DEPRECATION_WARNINGS
     ret->output_count = ret->nb_outputs;
     ret->input_count  = ret->nb_inputs;
+FF_ENABLE_DEPRECATION_WARNINGS
 #endif
 
     return ret;
@@ -614,6 +686,7 @@ err:
     av_freep(&ret->output_pads);
     ret->nb_outputs = 0;
     av_freep(&ret->priv);
+    av_freep(&ret->internal);
     av_free(ret);
     return NULL;
 }
@@ -681,6 +754,7 @@ void avfilter_free(AVFilterContext *filter)
     av_expr_free(filter->enable);
     filter->enable = NULL;
     av_freep(&filter->var_values);
+    av_freep(&filter->internal);
     av_free(filter);
 }
 
@@ -693,8 +767,6 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options,
     const char *key;
     int offset= -1;
 
-    av_opt_set_defaults(ctx);
-
     if (!args)
         return 0;
 
@@ -733,8 +805,11 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options,
 
         if (av_opt_find(ctx, key, NULL, 0, 0)) {
             ret = av_opt_set(ctx, key, value, 0);
-            if (ret < 0)
+            if (ret < 0) {
+                av_free(value);
+                av_free(parsed_key);
                 return ret;
+            }
         } else {
         av_dict_set(options, key, value, 0);
         if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) {
@@ -772,6 +847,21 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options)
 {
     int ret = 0;
 
+    ret = av_opt_set_dict(ctx, options);
+    if (ret < 0) {
+        av_log(ctx, AV_LOG_ERROR, "Error applying generic filter options.\n");
+        return ret;
+    }
+
+    if (ctx->filter->flags & AVFILTER_FLAG_SLICE_THREADS &&
+        ctx->thread_type & ctx->graph->thread_type & AVFILTER_THREAD_SLICE &&
+        ctx->graph->internal->thread_execute) {
+        ctx->thread_type       = AVFILTER_THREAD_SLICE;
+        ctx->internal->execute = ctx->graph->internal->thread_execute;
+    } else {
+        ctx->thread_type = 0;
+    }
+
     if (ctx->filter->priv_class) {
         ret = av_opt_set_dict(ctx->priv, options);
         if (ret < 0) {
@@ -875,21 +965,6 @@ int avfilter_init_str(AVFilterContext *filter, const char *args)
                 goto fail;
 #endif
         } else {
-#if CONFIG_MP_FILTER
-            if (!strcmp(filter->filter->name, "mp")) {
-                char *escaped;
-
-                if (!strncmp(args, "filter=", 7))
-                    args += 7;
-                ret = av_escape(&escaped, args, ":=", AV_ESCAPE_MODE_BACKSLASH, 0);
-                if (ret < 0) {
-                    av_log(filter, AV_LOG_ERROR, "Unable to escape MPlayer filters arg '%s'\n", args);
-                    goto fail;
-                }
-                ret = process_options(filter, &options, escaped);
-                av_free(escaped);
-            } else
-#endif
             ret = process_options(filter, &options, args);
             if (ret < 0)
                 goto fail;
@@ -932,7 +1007,7 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
     int (*filter_frame)(AVFilterLink *, AVFrame *);
     AVFilterContext *dstctx = link->dst;
     AVFilterPad *dst = link->dstpad;
-    AVFrame *out;
+    AVFrame *out = NULL;
     int ret;
     AVFilterCommand *cmd= link->dst->command_queue;
     int64_t pts;
@@ -957,13 +1032,18 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
         case AVMEDIA_TYPE_AUDIO:
             out = ff_get_audio_buffer(link, frame->nb_samples);
             break;
-        default: return AVERROR(EINVAL);
+        default:
+            ret = AVERROR(EINVAL);
+            goto fail;
         }
         if (!out) {
-            av_frame_free(&frame);
-            return AVERROR(ENOMEM);
+            ret = AVERROR(ENOMEM);
+            goto fail;
         }
-        av_frame_copy_props(out, frame);
+
+        ret = av_frame_copy_props(out, frame);
+        if (ret < 0)
+            goto fail;
 
         switch (link->type) {
         case AVMEDIA_TYPE_VIDEO:
@@ -976,7 +1056,9 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
                             av_get_channel_layout_nb_channels(frame->channel_layout),
                             frame->format);
             break;
-        default: return AVERROR(EINVAL);
+        default:
+            ret = AVERROR(EINVAL);
+            goto fail;
         }
 
         av_frame_free(&frame);
@@ -997,9 +1079,11 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
         int64_t pos = av_frame_get_pkt_pos(out);
         dstctx->var_values[VAR_N] = link->frame_count;
         dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base);
+        dstctx->var_values[VAR_W] = link->w;
+        dstctx->var_values[VAR_H] = link->h;
         dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos;
 
-        dstctx->is_disabled = !av_expr_eval(dstctx->enable, dstctx->var_values, NULL);
+        dstctx->is_disabled = fabs(av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) < 0.5;
         if (dstctx->is_disabled &&
             (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC))
             filter_frame = default_filter_frame;
@@ -1009,6 +1093,11 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
     link->frame_requested = 0;
     ff_update_link_current_pts(link, pts);
     return ret;
+
+fail:
+    av_frame_free(&out);
+    av_frame_free(&frame);
+    return ret;
 }
 
 static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
@@ -1030,8 +1119,9 @@ static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
                 return 0;
             }
             av_frame_copy_props(pbuf, frame);
-            pbuf->pts = frame->pts +
-                        av_rescale_q(inpos, samples_tb, link->time_base);
+            pbuf->pts = frame->pts;
+            if (pbuf->pts != AV_NOPTS_VALUE)
+                pbuf->pts += av_rescale_q(inpos, samples_tb, link->time_base);
             pbuf->nb_samples = 0;
         }
         nb_samples = FFMIN(insamples,
@@ -1058,7 +1148,8 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
 
     /* Consistency checks */
     if (link->type == AVMEDIA_TYPE_VIDEO) {
-        if (strcmp(link->dst->filter->name, "scale")) {
+        if (strcmp(link->dst->filter->name, "scale") &&
+            strcmp(link->dst->filter->name, "idet")) {
             av_assert1(frame->format                 == link->format);
             av_assert1(frame->width               == link->w);
             av_assert1(frame->height               == link->h);