lavfi/drawutils: make ff_draw_color() accept a const rgba map
[ffmpeg.git] / libavfilter / vsrc_testsrc.c
index a920314..5a16ee3 100644 (file)
@@ -50,6 +50,8 @@ typedef struct {
     char *duration;             ///< total duration of the generated video
     AVRational sar;             ///< sample aspect ratio
     int nb_decimals;
+    int draw_once;              ///< draw only the first frame, always put out the same picture
+    AVFilterBufferRef *picref;  ///< cached reference containing the painted picture
 
     void (* fill_picture_fn)(AVFilterContext *ctx, AVFilterBufferRef *picref);
 
@@ -59,7 +61,7 @@ typedef struct {
 
 #define OFFSET(x) offsetof(TestSourceContext, x)
 
-static const AVOption testsrc_options[]= {
+static const AVOption options[] = {
     { "size",     "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0 },
     { "s",        "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0 },
     { "rate",     "set video rate",     OFFSET(rate),     AV_OPT_TYPE_STRING, {.str = "25"},      0, 0 },
@@ -67,6 +69,8 @@ static const AVOption testsrc_options[]= {
     { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_STRING, {.str = NULL},      0, 0 },
     { "d",        "set video duration", OFFSET(duration), AV_OPT_TYPE_STRING, {.str = NULL},      0, 0 },
     { "sar",      "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl= 1},  0, INT_MAX },
+
+    /* only used by testsrc */
     { "decimals", "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.dbl=0},  INT_MIN, INT_MAX },
     { "n",        "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.dbl=0},  INT_MIN, INT_MAX },
     { NULL },
@@ -90,13 +94,11 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
         av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", test->rate);
         return ret;
     }
-    av_freep(&test->rate);
 
-    if ((test->duration) && (ret = av_parse_time(&duration, test->duration, 1)) < 0) {
+    if (test->duration && (ret = av_parse_time(&duration, test->duration, 1)) < 0) {
         av_log(ctx, AV_LOG_ERROR, "Invalid duration: '%s'\n", test->duration);
         return ret;
     }
-    av_freep(&test->duration);
 
     if (test->nb_decimals && strcmp(ctx->filter->name, "testsrc")) {
         av_log(ctx, AV_LOG_WARNING,
@@ -118,6 +120,14 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    TestSourceContext *test = ctx->priv;
+
+    av_opt_free(test);
+    avfilter_unref_bufferp(&test->picref);
+}
+
 static int config_props(AVFilterLink *outlink)
 {
     TestSourceContext *test = outlink->src->priv;
@@ -133,37 +143,51 @@ static int config_props(AVFilterLink *outlink)
 static int request_frame(AVFilterLink *outlink)
 {
     TestSourceContext *test = outlink->src->priv;
-    AVFilterBufferRef *picref;
+    AVFilterBufferRef *outpicref;
+    int ret = 0;
 
     if (test->max_pts >= 0 && test->pts >= test->max_pts)
         return AVERROR_EOF;
-    picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, test->w, test->h);
-    picref->pts = test->pts++;
-    picref->pos = -1;
-    picref->video->key_frame = 1;
-    picref->video->interlaced = 0;
-    picref->video->pict_type = AV_PICTURE_TYPE_I;
-    picref->video->sample_aspect_ratio = test->sar;
-    test->fill_picture_fn(outlink->src, picref);
+
+    if (test->draw_once) {
+        if (!test->picref) {
+            test->picref =
+                ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_PRESERVE|AV_PERM_REUSE,
+                                    test->w, test->h);
+            if (!test->picref)
+                return AVERROR(ENOMEM);
+            test->fill_picture_fn(outlink->src, test->picref);
+        }
+        outpicref = avfilter_ref_buffer(test->picref, ~AV_PERM_WRITE);
+    } else
+        outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, test->w, test->h);
+
+    if (!outpicref)
+        return AVERROR(ENOMEM);
+    outpicref->pts = test->pts;
+    outpicref->pos = -1;
+    outpicref->video->key_frame = 1;
+    outpicref->video->interlaced = 0;
+    outpicref->video->pict_type = AV_PICTURE_TYPE_I;
+    outpicref->video->sample_aspect_ratio = test->sar;
+    if (!test->draw_once)
+        test->fill_picture_fn(outlink->src, outpicref);
+
+    test->pts++;
     test->nb_frame++;
 
-    ff_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
-    ff_draw_slice(outlink, 0, picref->video->h, 1);
-    ff_end_frame(outlink);
-    avfilter_unref_buffer(picref);
+    if ((ret = ff_start_frame(outlink, outpicref)) < 0 ||
+        (ret = ff_draw_slice(outlink, 0, test->h, 1)) < 0 ||
+        (ret = ff_end_frame(outlink)) < 0)
+        return ret;
 
     return 0;
 }
 
 #if CONFIG_NULLSRC_FILTER
 
-static const AVClass nullsrc_class = {
-    .class_name = "nullsrc",
-    .item_name  = av_default_item_name,
-    .option     = testsrc_options,
-    .version    = LIBAVUTIL_VERSION_INT,
-    .category   = AV_CLASS_CATEGORY_FILTER,
-};
+#define nullsrc_options options
+AVFILTER_DEFINE_CLASS(nullsrc);
 
 static void nullsrc_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref) { }
 
@@ -180,6 +204,7 @@ AVFilter avfilter_vsrc_nullsrc = {
     .name        = "nullsrc",
     .description = NULL_IF_CONFIG_SMALL("Null video source, return unprocessed video frames."),
     .init       = nullsrc_init,
+    .uninit     = uninit,
     .priv_size  = sizeof(TestSourceContext),
 
     .inputs    = (const AVFilterPad[]) {{ .name = NULL}},
@@ -194,6 +219,7 @@ AVFilter avfilter_vsrc_nullsrc = {
 
 #if CONFIG_TESTSRC_FILTER
 
+#define testsrc_options options
 AVFILTER_DEFINE_CLASS(testsrc);
 
 /**
@@ -396,29 +422,25 @@ AVFilter avfilter_vsrc_testsrc = {
     .description = NULL_IF_CONFIG_SMALL("Generate test pattern."),
     .priv_size = sizeof(TestSourceContext),
     .init      = test_init,
+    .uninit    = uninit,
 
     .query_formats   = test_query_formats,
 
     .inputs    = (const AVFilterPad[]) {{ .name = NULL}},
 
     .outputs   = (const AVFilterPad[]) {{ .name = "default",
-                                    .type = AVMEDIA_TYPE_VIDEO,
-                                    .request_frame = request_frame,
-                                    .config_props  = config_props, },
-                                  { .name = NULL }},
+                                          .type = AVMEDIA_TYPE_VIDEO,
+                                          .request_frame = request_frame,
+                                          .config_props  = config_props, },
+                                        { .name = NULL }},
 };
 
 #endif /* CONFIG_TESTSRC_FILTER */
 
 #if CONFIG_RGBTESTSRC_FILTER
 
-static const AVClass rgbtestsrc_class = {
-    .class_name = "rgbtestsrc",
-    .item_name  = av_default_item_name,
-    .option     = testsrc_options,
-    .version    = LIBAVUTIL_VERSION_INT,
-    .category   = AV_CLASS_CATEGORY_FILTER,
-};
+#define rgbtestsrc_options options
+AVFILTER_DEFINE_CLASS(rgbtestsrc);
 
 #define R 0
 #define G 1
@@ -480,6 +502,7 @@ static av_cold int rgbtest_init(AVFilterContext *ctx, const char *args)
 {
     TestSourceContext *test = ctx->priv;
 
+    test->draw_once = 1;
     test->class = &rgbtestsrc_class;
     test->fill_picture_fn = rgbtest_fill_picture;
     return init(ctx, args);
@@ -520,16 +543,17 @@ AVFilter avfilter_vsrc_rgbtestsrc = {
     .description = NULL_IF_CONFIG_SMALL("Generate RGB test pattern."),
     .priv_size = sizeof(TestSourceContext),
     .init      = rgbtest_init,
+    .uninit    = uninit,
 
     .query_formats   = rgbtest_query_formats,
 
     .inputs    = (const AVFilterPad[]) {{ .name = NULL}},
 
     .outputs   = (const AVFilterPad[]) {{ .name = "default",
-                                    .type = AVMEDIA_TYPE_VIDEO,
-                                    .request_frame = request_frame,
-                                    .config_props  = rgbtest_config_props, },
-                                  { .name = NULL }},
+                                          .type = AVMEDIA_TYPE_VIDEO,
+                                          .request_frame = request_frame,
+                                          .config_props  = rgbtest_config_props, },
+                                        { .name = NULL }},
 };
 
 #endif /* CONFIG_RGBTESTSRC_FILTER */