00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "avfilter.h"
00027 #include "formats.h"
00028 #include "internal.h"
00029 #include "video.h"
00030 #include "libavutil/pixdesc.h"
00031 #include "libavutil/colorspace.h"
00032 #include "libavutil/imgutils.h"
00033 #include "libavutil/mathematics.h"
00034 #include "libavutil/opt.h"
00035 #include "libavutil/parseutils.h"
00036 #include "drawutils.h"
00037
00038 typedef struct {
00039 const AVClass *class;
00040 int w, h;
00041 char *rate_str;
00042 char *color_str;
00043 uint8_t color_rgba[4];
00044 AVRational time_base;
00045 uint64_t pts;
00046 FFDrawContext draw;
00047 FFDrawColor color;
00048 AVFilterBufferRef *picref;
00049 } ColorContext;
00050
00051 #define OFFSET(x) offsetof(ColorContext, x)
00052
00053 static const AVOption color_options[]= {
00054 { "size", "set frame size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0 },
00055 { "s", "set frame size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0 },
00056 { "rate", "set frame rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0 },
00057 { "r", "set frame rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0 },
00058 { "color", "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX },
00059 { "c", "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX },
00060 { NULL },
00061 };
00062
00063 AVFILTER_DEFINE_CLASS(color);
00064
00065 static av_cold int color_init(AVFilterContext *ctx, const char *args)
00066 {
00067 ColorContext *color = ctx->priv;
00068 AVRational frame_rate_q;
00069 int ret = 0;
00070
00071 color->class = &color_class;
00072
00073 av_opt_set_defaults(color);
00074 if ((ret = av_set_options_string(color, args, "=", ":")) < 0) {
00075 av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
00076 goto end;
00077 }
00078 if (av_parse_video_rate(&frame_rate_q, color->rate_str) < 0) {
00079 av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: %s\n", color->rate_str);
00080 ret = AVERROR(EINVAL);
00081 goto end;
00082 }
00083 if (av_parse_color(color->color_rgba, color->color_str, -1, ctx) < 0) {
00084 ret = AVERROR(EINVAL);
00085 goto end;
00086 }
00087
00088 color->time_base.num = frame_rate_q.den;
00089 color->time_base.den = frame_rate_q.num;
00090
00091 end:
00092 return ret;
00093 }
00094
00095 static av_cold void color_uninit(AVFilterContext *ctx)
00096 {
00097 ColorContext *color = ctx->priv;
00098 av_opt_free(color);
00099 avfilter_unref_bufferp(&color->picref);
00100 }
00101
00102 static int query_formats(AVFilterContext *ctx)
00103 {
00104 ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
00105 return 0;
00106 }
00107
00108 static int color_config_props(AVFilterLink *inlink)
00109 {
00110 AVFilterContext *ctx = inlink->src;
00111 ColorContext *color = ctx->priv;
00112
00113 ff_draw_init(&color->draw, inlink->format, 0);
00114 ff_draw_color(&color->draw, &color->color, color->color_rgba);
00115
00116 color->w = ff_draw_round_to_sub(&color->draw, 0, -1, color->w);
00117 color->h = ff_draw_round_to_sub(&color->draw, 1, -1, color->h);
00118 if (av_image_check_size(color->w, color->h, 0, ctx) < 0)
00119 return AVERROR(EINVAL);
00120
00121 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d r:%d/%d color:0x%02x%02x%02x%02x\n",
00122 color->w, color->h, color->time_base.den, color->time_base.num,
00123 color->color_rgba[0], color->color_rgba[1], color->color_rgba[2], color->color_rgba[3]);
00124 inlink->w = color->w;
00125 inlink->h = color->h;
00126 inlink->time_base = color->time_base;
00127
00128 return 0;
00129 }
00130
00131 static int color_request_frame(AVFilterLink *link)
00132 {
00133 ColorContext *color = link->src->priv;
00134 AVFilterBufferRef *buf_out;
00135 int ret;
00136
00137 if (!color->picref) {
00138 color->picref =
00139 ff_get_video_buffer(link, AV_PERM_WRITE|AV_PERM_PRESERVE|AV_PERM_REUSE,
00140 color->w, color->h);
00141 if (!color->picref)
00142 return AVERROR(ENOMEM);
00143 ff_fill_rectangle(&color->draw, &color->color,
00144 color->picref->data, color->picref->linesize,
00145 0, 0, color->w, color->h);
00146 color->picref->video->sample_aspect_ratio = (AVRational) {1, 1};
00147 color->picref->pos = -1;
00148 }
00149
00150 color->picref->pts = color->pts++;
00151 buf_out = avfilter_ref_buffer(color->picref, ~AV_PERM_WRITE);
00152 if (!buf_out) {
00153 ret = AVERROR(ENOMEM);
00154 goto fail;
00155 }
00156
00157 ret = ff_start_frame(link, buf_out);
00158 if (ret < 0)
00159 goto fail;
00160
00161 ret = ff_draw_slice(link, 0, color->h, 1);
00162 if (ret < 0)
00163 goto fail;
00164
00165 ret = ff_end_frame(link);
00166
00167 fail:
00168 return ret;
00169 }
00170
00171 AVFilter avfilter_vsrc_color = {
00172 .name = "color",
00173 .description = NULL_IF_CONFIG_SMALL("Provide an uniformly colored input."),
00174
00175 .priv_size = sizeof(ColorContext),
00176 .init = color_init,
00177 .uninit = color_uninit,
00178
00179 .query_formats = query_formats,
00180
00181 .inputs = (const AVFilterPad[]) {{ .name = NULL}},
00182
00183 .outputs = (const AVFilterPad[]) {{ .name = "default",
00184 .type = AVMEDIA_TYPE_VIDEO,
00185 .request_frame = color_request_frame,
00186 .config_props = color_config_props },
00187 { .name = NULL}},
00188 };