avfiltergraph: Properly handle memory allocation failure
[ffmpeg.git] / libavfilter / avf_concat.c
index 634b9d7..4b02ac8 100644 (file)
@@ -68,8 +68,8 @@ static const AVOption concat_options[] = {
       AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A|F},
     { "unsafe", "enable unsafe mode",
       OFFSET(unsafe),
-      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A|A|F},
-    { 0 }
+      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V|A|F},
+    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(concat);
@@ -134,10 +134,13 @@ static int config_output(AVFilterLink *outlink)
     outlink->format              = inlink->format;
     for (seg = 1; seg < cat->nb_segments; seg++) {
         inlink = ctx->inputs[in_no += ctx->nb_outputs];
+        if (!outlink->sample_aspect_ratio.num)
+            outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
         /* possible enhancement: unsafe mode, do not check */
         if (outlink->w                       != inlink->w                       ||
             outlink->h                       != inlink->h                       ||
-            outlink->sample_aspect_ratio.num != inlink->sample_aspect_ratio.num ||
+            outlink->sample_aspect_ratio.num != inlink->sample_aspect_ratio.num &&
+                                                inlink->sample_aspect_ratio.num ||
             outlink->sample_aspect_ratio.den != inlink->sample_aspect_ratio.den) {
             av_log(ctx, AV_LOG_ERROR, "Input link %s parameters "
                    "(size %dx%d, SAR %d:%d) do not match the corresponding "
@@ -156,8 +159,7 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static void push_frame(AVFilterContext *ctx, unsigned in_no,
-                       AVFrame *buf)
+static int push_frame(AVFilterContext *ctx, unsigned in_no, AVFrame *buf)
 {
     ConcatContext *cat = ctx->priv;
     unsigned out_no = in_no % ctx->nb_outputs;
@@ -179,10 +181,10 @@ static void push_frame(AVFilterContext *ctx, unsigned in_no,
         in->pts = av_rescale(in->pts, in->nb_frames, in->nb_frames - 1);
 
     buf->pts += cat->delta_ts;
-    ff_filter_frame(outlink, buf);
+    return ff_filter_frame(outlink, buf);
 }
 
-static void process_frame(AVFilterLink *inlink, AVFrame *buf)
+static int process_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext *ctx  = inlink->dst;
     ConcatContext *cat    = ctx->priv;
@@ -195,8 +197,9 @@ static void process_frame(AVFilterLink *inlink, AVFrame *buf)
     } else if (in_no >= cat->cur_idx + ctx->nb_outputs) {
         ff_bufqueue_add(ctx, &cat->in[in_no].queue, buf);
     } else {
-        push_frame(ctx, in_no, buf);
+        return push_frame(ctx, in_no, buf);
     }
+    return 0;
 }
 
 static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
@@ -219,8 +222,7 @@ static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
-    process_frame(inlink, buf);
-    return 0; /* enhancement: handle error return */
+    return process_frame(inlink, buf);
 }
 
 static void close_input(AVFilterContext *ctx, unsigned in_no)
@@ -233,7 +235,7 @@ static void close_input(AVFilterContext *ctx, unsigned in_no)
            ctx->input_pads[in_no].name, cat->nb_in_active);
 }
 
-static void find_next_delta_ts(AVFilterContext *ctx)
+static void find_next_delta_ts(AVFilterContext *ctx, int64_t *seg_delta)
 {
     ConcatContext *cat = ctx->priv;
     unsigned i = cat->cur_idx;
@@ -244,44 +246,51 @@ static void find_next_delta_ts(AVFilterContext *ctx)
     for (; i < imax; i++)
         pts = FFMAX(pts, cat->in[i].pts);
     cat->delta_ts += pts;
+    *seg_delta = pts;
 }
 
-static void send_silence(AVFilterContext *ctx, unsigned in_no, unsigned out_no)
+static int send_silence(AVFilterContext *ctx, unsigned in_no, unsigned out_no,
+                        int64_t seg_delta)
 {
     ConcatContext *cat = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[out_no];
-    int64_t base_pts = cat->in[in_no].pts + cat->delta_ts;
+    int64_t base_pts = cat->in[in_no].pts + cat->delta_ts - seg_delta;
     int64_t nb_samples, sent = 0;
-    int frame_nb_samples;
+    int frame_nb_samples, ret;
     AVRational rate_tb = { 1, ctx->inputs[in_no]->sample_rate };
     AVFrame *buf;
     int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
 
     if (!rate_tb.den)
-        return;
-    nb_samples = av_rescale_q(cat->delta_ts - base_pts,
+        return AVERROR_BUG;
+    nb_samples = av_rescale_q(seg_delta - cat->in[in_no].pts,
                               outlink->time_base, rate_tb);
     frame_nb_samples = FFMAX(9600, rate_tb.den / 5); /* arbitrary */
     while (nb_samples) {
         frame_nb_samples = FFMIN(frame_nb_samples, nb_samples);
         buf = ff_get_audio_buffer(outlink, frame_nb_samples);
         if (!buf)
-            return;
+            return AVERROR(ENOMEM);
         av_samples_set_silence(buf->extended_data, 0, frame_nb_samples,
                                nb_channels, outlink->format);
         buf->pts = base_pts + av_rescale_q(sent, rate_tb, outlink->time_base);
-        ff_filter_frame(outlink, buf);
+        ret = ff_filter_frame(outlink, buf);
+        if (ret < 0)
+            return ret;
         sent       += frame_nb_samples;
         nb_samples -= frame_nb_samples;
     }
+    return 0;
 }
 
-static void flush_segment(AVFilterContext *ctx)
+static int flush_segment(AVFilterContext *ctx)
 {
+    int ret;
     ConcatContext *cat = ctx->priv;
     unsigned str, str_max;
+    int64_t seg_delta;
 
-    find_next_delta_ts(ctx);
+    find_next_delta_ts(ctx, &seg_delta);
     cat->cur_idx += ctx->nb_outputs;
     cat->nb_in_active = ctx->nb_outputs;
     av_log(ctx, AV_LOG_VERBOSE, "Segment finished at pts=%"PRId64"\n",
@@ -291,15 +300,24 @@ static void flush_segment(AVFilterContext *ctx)
         /* pad audio streams with silence */
         str = cat->nb_streams[AVMEDIA_TYPE_VIDEO];
         str_max = str + cat->nb_streams[AVMEDIA_TYPE_AUDIO];
-        for (; str < str_max; str++)
-            send_silence(ctx, cat->cur_idx - ctx->nb_outputs + str, str);
+        for (; str < str_max; str++) {
+            ret = send_silence(ctx, cat->cur_idx - ctx->nb_outputs + str, str,
+                               seg_delta);
+            if (ret < 0)
+                return ret;
+        }
         /* flush queued buffers */
         /* possible enhancement: flush in PTS order */
         str_max = cat->cur_idx + ctx->nb_outputs;
-        for (str = cat->cur_idx; str < str_max; str++)
-            while (cat->in[str].queue.available)
-                push_frame(ctx, str, ff_bufqueue_get(&cat->in[str].queue));
+        for (str = cat->cur_idx; str < str_max; str++) {
+            while (cat->in[str].queue.available) {
+                ret = push_frame(ctx, str, ff_bufqueue_get(&cat->in[str].queue));
+                if (ret < 0)
+                    return ret;
+            }
+        }
     }
+    return 0;
 }
 
 static int request_frame(AVFilterLink *outlink)
@@ -333,25 +351,18 @@ static int request_frame(AVFilterLink *outlink)
             else if (ret < 0)
                 return ret;
         }
-        flush_segment(ctx);
+        ret = flush_segment(ctx);
+        if (ret < 0)
+            return ret;
         in_no += ctx->nb_outputs;
     }
 }
 
-static av_cold int init(AVFilterContext *ctx, const char *args)
+static av_cold int init(AVFilterContext *ctx)
 {
     ConcatContext *cat = ctx->priv;
-    int ret;
     unsigned seg, type, str;
 
-    cat->class = &concat_class;
-    av_opt_set_defaults(cat);
-    ret = av_set_options_string(cat, args, "=", ":");
-    if (ret < 0) {
-        av_log(ctx, AV_LOG_ERROR, "Error parsing options: '%s'\n", args);
-        return ret;
-    }
-
     /* create input pads */
     for (seg = 0; seg < cat->nb_segments; seg++) {
         for (type = 0; type < TYPE_ALL; type++) {
@@ -411,4 +422,5 @@ AVFilter avfilter_avf_concat = {
     .inputs        = NULL,
     .outputs       = NULL,
     .priv_class    = &concat_class,
+    .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };