lavfi/testsrc: add support for color interactive command
[ffmpeg.git] / libavfilter / vsrc_testsrc.c
1 /*
2  * Copyright (c) 2007 Nicolas George <nicolas.george@normalesup.org>
3  * Copyright (c) 2011 Stefano Sabatini
4  * Copyright (c) 2012 Paul B Mahol
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 /**
24  * @file
25  * Misc test sources.
26  *
27  * testsrc is based on the test pattern generator demuxer by Nicolas George:
28  * http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2007-October/037845.html
29  *
30  * rgbtestsrc is ported from MPlayer libmpcodecs/vf_rgbtest.c by
31  * Michael Niedermayer.
32  *
33  * smptebars and smptehdbars are by Paul B Mahol.
34  */
35
36 #include <float.h>
37
38 #include "libavutil/avassert.h"
39 #include "libavutil/common.h"
40 #include "libavutil/opt.h"
41 #include "libavutil/imgutils.h"
42 #include "libavutil/intreadwrite.h"
43 #include "libavutil/parseutils.h"
44 #include "avfilter.h"
45 #include "drawutils.h"
46 #include "formats.h"
47 #include "internal.h"
48 #include "video.h"
49
50 typedef struct {
51     const AVClass *class;
52     int w, h;
53     unsigned int nb_frame;
54     AVRational time_base, frame_rate;
55     int64_t pts;
56     int64_t duration;           ///< duration expressed in microseconds
57     AVRational sar;             ///< sample aspect ratio
58     int nb_decimals;
59     int draw_once;              ///< draw only the first frame, always put out the same picture
60     int draw_once_reset;        ///< draw only the first frame or in case of reset
61     AVFrame *picref;            ///< cached reference containing the painted picture
62
63     void (* fill_picture_fn)(AVFilterContext *ctx, AVFrame *frame);
64
65     /* only used by color */
66     char *color_str;
67     FFDrawContext draw;
68     FFDrawColor color;
69     uint8_t color_rgba[4];
70
71     /* only used by rgbtest */
72     uint8_t rgba_map[4];
73 } TestSourceContext;
74
75 #define OFFSET(x) offsetof(TestSourceContext, x)
76 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
77
78 #define COMMON_OPTIONS \
79     { "size",     "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
80     { "s",        "set video size",     OFFSET(w),        AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
81     { "rate",     "set video rate",     OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
82     { "r",        "set video rate",     OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
83     { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\
84     { "d",        "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\
85     { "sar",      "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl= 1},  0, INT_MAX, FLAGS },
86
87
88 static const AVOption color_options[] = {
89     /* only used by color */
90     { "color", "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
91     { "c",     "set color", OFFSET(color_str), AV_OPT_TYPE_STRING, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
92
93     COMMON_OPTIONS
94     { NULL },
95 };
96
97 static const AVOption options[] = {
98     COMMON_OPTIONS
99     /* only used by testsrc */
100     { "decimals", "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.i64=0},  0, 17, FLAGS },
101     { "n",        "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.i64=0},  0, 17, FLAGS },
102
103     { NULL },
104 };
105
106 static av_cold int init(AVFilterContext *ctx)
107 {
108     TestSourceContext *test = ctx->priv;
109     int ret = 0;
110
111     if (test->nb_decimals && strcmp(ctx->filter->name, "testsrc")) {
112         av_log(ctx, AV_LOG_WARNING,
113                "Option 'decimals' is ignored with source '%s'\n",
114                ctx->filter->name);
115     }
116
117     if (test->color_str) {
118         if (!strcmp(ctx->filter->name, "color")) {
119             ret = av_parse_color(test->color_rgba, test->color_str, -1, ctx);
120             if (ret < 0)
121                 return ret;
122         } else {
123             av_log(ctx, AV_LOG_WARNING,
124                    "Option 'color' is ignored with source '%s'\n",
125                    ctx->filter->name);
126         }
127     }
128
129     test->time_base = av_inv_q(test->frame_rate);
130     test->nb_frame = 0;
131     test->pts = 0;
132
133     av_log(ctx, AV_LOG_VERBOSE, "size:%dx%d rate:%d/%d duration:%f sar:%d/%d\n",
134            test->w, test->h, test->frame_rate.num, test->frame_rate.den,
135            test->duration < 0 ? -1 : (double)test->duration/1000000,
136            test->sar.num, test->sar.den);
137     return 0;
138 }
139
140 static av_cold void uninit(AVFilterContext *ctx)
141 {
142     TestSourceContext *test = ctx->priv;
143
144     av_frame_free(&test->picref);
145 }
146
147 static int config_props(AVFilterLink *outlink)
148 {
149     TestSourceContext *test = outlink->src->priv;
150
151     outlink->w = test->w;
152     outlink->h = test->h;
153     outlink->sample_aspect_ratio = test->sar;
154     outlink->frame_rate = test->frame_rate;
155     outlink->time_base  = test->time_base;
156
157     return 0;
158 }
159
160 static int request_frame(AVFilterLink *outlink)
161 {
162     TestSourceContext *test = outlink->src->priv;
163     AVFrame *frame;
164
165     if (test->duration >= 0 &&
166         av_rescale_q(test->pts, test->time_base, AV_TIME_BASE_Q) >= test->duration)
167         return AVERROR_EOF;
168
169     if (test->draw_once) {
170         if (test->draw_once_reset) {
171             av_frame_free(&test->picref);
172             test->draw_once_reset = 0;
173         }
174         if (!test->picref) {
175             test->picref =
176                 ff_get_video_buffer(outlink, test->w, test->h);
177             if (!test->picref)
178                 return AVERROR(ENOMEM);
179             test->fill_picture_fn(outlink->src, test->picref);
180         }
181         frame = av_frame_clone(test->picref);
182     } else
183         frame = ff_get_video_buffer(outlink, test->w, test->h);
184
185     if (!frame)
186         return AVERROR(ENOMEM);
187     frame->pts                 = test->pts;
188     frame->key_frame           = 1;
189     frame->interlaced_frame    = 0;
190     frame->pict_type           = AV_PICTURE_TYPE_I;
191     frame->sample_aspect_ratio = test->sar;
192     if (!test->draw_once)
193         test->fill_picture_fn(outlink->src, frame);
194
195     test->pts++;
196     test->nb_frame++;
197
198     return ff_filter_frame(outlink, frame);
199 }
200
201 #if CONFIG_COLOR_FILTER
202
203 AVFILTER_DEFINE_CLASS(color);
204
205 static void color_fill_picture(AVFilterContext *ctx, AVFrame *picref)
206 {
207     TestSourceContext *test = ctx->priv;
208     ff_fill_rectangle(&test->draw, &test->color,
209                       picref->data, picref->linesize,
210                       0, 0, test->w, test->h);
211 }
212
213 static av_cold int color_init(AVFilterContext *ctx)
214 {
215     TestSourceContext *test = ctx->priv;
216     test->fill_picture_fn = color_fill_picture;
217     test->draw_once = 1;
218     return init(ctx);
219 }
220
221 static int color_query_formats(AVFilterContext *ctx)
222 {
223     ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
224     return 0;
225 }
226
227 static int color_config_props(AVFilterLink *inlink)
228 {
229     AVFilterContext *ctx = inlink->src;
230     TestSourceContext *test = ctx->priv;
231     int ret;
232
233     ff_draw_init(&test->draw, inlink->format, 0);
234     ff_draw_color(&test->draw, &test->color, test->color_rgba);
235
236     test->w = ff_draw_round_to_sub(&test->draw, 0, -1, test->w);
237     test->h = ff_draw_round_to_sub(&test->draw, 1, -1, test->h);
238     if (av_image_check_size(test->w, test->h, 0, ctx) < 0)
239         return AVERROR(EINVAL);
240
241     if ((ret = config_props(inlink)) < 0)
242         return ret;
243
244     av_log(ctx, AV_LOG_VERBOSE, "color:0x%02x%02x%02x%02x\n",
245            test->color_rgba[0], test->color_rgba[1], test->color_rgba[2], test->color_rgba[3]);
246     return 0;
247 }
248
249 static int color_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
250                                  char *res, int res_len, int flags)
251 {
252     TestSourceContext *test = ctx->priv;
253     int ret;
254
255     if (!strcmp(cmd, "color") || !strcmp(cmd, "c")) {
256         char *color_str;
257         uint8_t color_rgba[4];
258
259         ret = av_parse_color(color_rgba, args, -1, ctx);
260         if (ret < 0)
261             return ret;
262         color_str = av_strdup(args);
263         if (!color_str)
264             return AVERROR(ENOMEM);
265         av_free(test->color_str);
266         test->color_str = color_str;
267
268         memcpy(test->color_rgba, color_rgba, sizeof(color_rgba));
269         ff_draw_color(&test->draw, &test->color, test->color_rgba);
270         test->draw_once_reset = 1;
271         return 0;
272     }
273
274     return AVERROR(ENOSYS);
275 }
276
277 static const AVFilterPad color_outputs[] = {
278     {
279         .name          = "default",
280         .type          = AVMEDIA_TYPE_VIDEO,
281         .request_frame = request_frame,
282         .config_props  = color_config_props,
283     },
284     {  NULL }
285 };
286
287 AVFilter avfilter_vsrc_color = {
288     .name        = "color",
289     .description = NULL_IF_CONFIG_SMALL("Provide an uniformly colored input."),
290
291     .priv_class = &color_class,
292     .priv_size = sizeof(TestSourceContext),
293     .init      = color_init,
294     .uninit    = uninit,
295
296     .query_formats = color_query_formats,
297     .inputs        = NULL,
298     .outputs       = color_outputs,
299     .process_command = color_process_command,
300 };
301
302 #endif /* CONFIG_COLOR_FILTER */
303
304 #if CONFIG_NULLSRC_FILTER
305
306 #define nullsrc_options options
307 AVFILTER_DEFINE_CLASS(nullsrc);
308
309 static void nullsrc_fill_picture(AVFilterContext *ctx, AVFrame *picref) { }
310
311 static av_cold int nullsrc_init(AVFilterContext *ctx)
312 {
313     TestSourceContext *test = ctx->priv;
314
315     test->fill_picture_fn = nullsrc_fill_picture;
316     return init(ctx);
317 }
318
319 static const AVFilterPad nullsrc_outputs[] = {
320     {
321         .name          = "default",
322         .type          = AVMEDIA_TYPE_VIDEO,
323         .request_frame = request_frame,
324         .config_props  = config_props,
325     },
326     { NULL },
327 };
328
329 AVFilter avfilter_vsrc_nullsrc = {
330     .name        = "nullsrc",
331     .description = NULL_IF_CONFIG_SMALL("Null video source, return unprocessed video frames."),
332     .init       = nullsrc_init,
333     .uninit     = uninit,
334     .priv_size  = sizeof(TestSourceContext),
335     .priv_class = &nullsrc_class,
336     .inputs     = NULL,
337     .outputs    = nullsrc_outputs,
338 };
339
340 #endif /* CONFIG_NULLSRC_FILTER */
341
342 #if CONFIG_TESTSRC_FILTER
343
344 #define testsrc_options options
345 AVFILTER_DEFINE_CLASS(testsrc);
346
347 /**
348  * Fill a rectangle with value val.
349  *
350  * @param val the RGB value to set
351  * @param dst pointer to the destination buffer to fill
352  * @param dst_linesize linesize of destination
353  * @param segment_width width of the segment
354  * @param x horizontal coordinate where to draw the rectangle in the destination buffer
355  * @param y horizontal coordinate where to draw the rectangle in the destination buffer
356  * @param w width  of the rectangle to draw, expressed as a number of segment_width units
357  * @param h height of the rectangle to draw, expressed as a number of segment_width units
358  */
359 static void draw_rectangle(unsigned val, uint8_t *dst, int dst_linesize, int segment_width,
360                            int x, int y, int w, int h)
361 {
362     int i;
363     int step = 3;
364
365     dst += segment_width * (step * x + y * dst_linesize);
366     w *= segment_width * step;
367     h *= segment_width;
368     for (i = 0; i < h; i++) {
369         memset(dst, val, w);
370         dst += dst_linesize;
371     }
372 }
373
374 static void draw_digit(int digit, uint8_t *dst, int dst_linesize,
375                        int segment_width)
376 {
377 #define TOP_HBAR        1
378 #define MID_HBAR        2
379 #define BOT_HBAR        4
380 #define LEFT_TOP_VBAR   8
381 #define LEFT_BOT_VBAR  16
382 #define RIGHT_TOP_VBAR 32
383 #define RIGHT_BOT_VBAR 64
384     struct {
385         int x, y, w, h;
386     } segments[] = {
387         { 1,  0, 5, 1 }, /* TOP_HBAR */
388         { 1,  6, 5, 1 }, /* MID_HBAR */
389         { 1, 12, 5, 1 }, /* BOT_HBAR */
390         { 0,  1, 1, 5 }, /* LEFT_TOP_VBAR */
391         { 0,  7, 1, 5 }, /* LEFT_BOT_VBAR */
392         { 6,  1, 1, 5 }, /* RIGHT_TOP_VBAR */
393         { 6,  7, 1, 5 }  /* RIGHT_BOT_VBAR */
394     };
395     static const unsigned char masks[10] = {
396         /* 0 */ TOP_HBAR         |BOT_HBAR|LEFT_TOP_VBAR|LEFT_BOT_VBAR|RIGHT_TOP_VBAR|RIGHT_BOT_VBAR,
397         /* 1 */                                                        RIGHT_TOP_VBAR|RIGHT_BOT_VBAR,
398         /* 2 */ TOP_HBAR|MID_HBAR|BOT_HBAR|LEFT_BOT_VBAR                             |RIGHT_TOP_VBAR,
399         /* 3 */ TOP_HBAR|MID_HBAR|BOT_HBAR                            |RIGHT_TOP_VBAR|RIGHT_BOT_VBAR,
400         /* 4 */          MID_HBAR         |LEFT_TOP_VBAR              |RIGHT_TOP_VBAR|RIGHT_BOT_VBAR,
401         /* 5 */ TOP_HBAR|BOT_HBAR|MID_HBAR|LEFT_TOP_VBAR                             |RIGHT_BOT_VBAR,
402         /* 6 */ TOP_HBAR|BOT_HBAR|MID_HBAR|LEFT_TOP_VBAR|LEFT_BOT_VBAR               |RIGHT_BOT_VBAR,
403         /* 7 */ TOP_HBAR                                              |RIGHT_TOP_VBAR|RIGHT_BOT_VBAR,
404         /* 8 */ TOP_HBAR|BOT_HBAR|MID_HBAR|LEFT_TOP_VBAR|LEFT_BOT_VBAR|RIGHT_TOP_VBAR|RIGHT_BOT_VBAR,
405         /* 9 */ TOP_HBAR|BOT_HBAR|MID_HBAR|LEFT_TOP_VBAR              |RIGHT_TOP_VBAR|RIGHT_BOT_VBAR,
406     };
407     unsigned mask = masks[digit];
408     int i;
409
410     draw_rectangle(0, dst, dst_linesize, segment_width, 0, 0, 8, 13);
411     for (i = 0; i < FF_ARRAY_ELEMS(segments); i++)
412         if (mask & (1<<i))
413             draw_rectangle(255, dst, dst_linesize, segment_width,
414                            segments[i].x, segments[i].y, segments[i].w, segments[i].h);
415 }
416
417 #define GRADIENT_SIZE (6 * 256)
418
419 static void test_fill_picture(AVFilterContext *ctx, AVFrame *frame)
420 {
421     TestSourceContext *test = ctx->priv;
422     uint8_t *p, *p0;
423     int x, y;
424     int color, color_rest;
425     int icolor;
426     int radius;
427     int quad0, quad;
428     int dquad_x, dquad_y;
429     int grad, dgrad, rgrad, drgrad;
430     int seg_size;
431     int second;
432     int i;
433     uint8_t *data = frame->data[0];
434     int width  = frame->width;
435     int height = frame->height;
436
437     /* draw colored bars and circle */
438     radius = (width + height) / 4;
439     quad0 = width * width / 4 + height * height / 4 - radius * radius;
440     dquad_y = 1 - height;
441     p0 = data;
442     for (y = 0; y < height; y++) {
443         p = p0;
444         color = 0;
445         color_rest = 0;
446         quad = quad0;
447         dquad_x = 1 - width;
448         for (x = 0; x < width; x++) {
449             icolor = color;
450             if (quad < 0)
451                 icolor ^= 7;
452             quad += dquad_x;
453             dquad_x += 2;
454             *(p++) = icolor & 1 ? 255 : 0;
455             *(p++) = icolor & 2 ? 255 : 0;
456             *(p++) = icolor & 4 ? 255 : 0;
457             color_rest += 8;
458             if (color_rest >= width) {
459                 color_rest -= width;
460                 color++;
461             }
462         }
463         quad0 += dquad_y;
464         dquad_y += 2;
465         p0 += frame->linesize[0];
466     }
467
468     /* draw sliding color line */
469     p0 = p = data + frame->linesize[0] * height * 3/4;
470     grad = (256 * test->nb_frame * test->time_base.num / test->time_base.den) %
471         GRADIENT_SIZE;
472     rgrad = 0;
473     dgrad = GRADIENT_SIZE / width;
474     drgrad = GRADIENT_SIZE % width;
475     for (x = 0; x < width; x++) {
476         *(p++) =
477             grad < 256 || grad >= 5 * 256 ? 255 :
478             grad >= 2 * 256 && grad < 4 * 256 ? 0 :
479             grad < 2 * 256 ? 2 * 256 - 1 - grad : grad - 4 * 256;
480         *(p++) =
481             grad >= 4 * 256 ? 0 :
482             grad >= 1 * 256 && grad < 3 * 256 ? 255 :
483             grad < 1 * 256 ? grad : 4 * 256 - 1 - grad;
484         *(p++) =
485             grad < 2 * 256 ? 0 :
486             grad >= 3 * 256 && grad < 5 * 256 ? 255 :
487             grad < 3 * 256 ? grad - 2 * 256 : 6 * 256 - 1 - grad;
488         grad += dgrad;
489         rgrad += drgrad;
490         if (rgrad >= GRADIENT_SIZE) {
491             grad++;
492             rgrad -= GRADIENT_SIZE;
493         }
494         if (grad >= GRADIENT_SIZE)
495             grad -= GRADIENT_SIZE;
496     }
497     p = p0;
498     for (y = height / 8; y > 0; y--) {
499         memcpy(p+frame->linesize[0], p, 3 * width);
500         p += frame->linesize[0];
501     }
502
503     /* draw digits */
504     seg_size = width / 80;
505     if (seg_size >= 1 && height >= 13 * seg_size) {
506         int64_t p10decimals = 1;
507         double time = av_q2d(test->time_base) * test->nb_frame *
508                       pow(10, test->nb_decimals);
509         if (time >= INT_MAX)
510             return;
511
512         for (x = 0; x < test->nb_decimals; x++)
513             p10decimals *= 10;
514
515         second = av_rescale_rnd(test->nb_frame * test->time_base.num, p10decimals, test->time_base.den, AV_ROUND_ZERO);
516         x = width - (width - seg_size * 64) / 2;
517         y = (height - seg_size * 13) / 2;
518         p = data + (x*3 + y * frame->linesize[0]);
519         for (i = 0; i < 8; i++) {
520             p -= 3 * 8 * seg_size;
521             draw_digit(second % 10, p, frame->linesize[0], seg_size);
522             second /= 10;
523             if (second == 0)
524                 break;
525         }
526     }
527 }
528
529 static av_cold int test_init(AVFilterContext *ctx)
530 {
531     TestSourceContext *test = ctx->priv;
532
533     test->fill_picture_fn = test_fill_picture;
534     return init(ctx);
535 }
536
537 static int test_query_formats(AVFilterContext *ctx)
538 {
539     static const enum AVPixelFormat pix_fmts[] = {
540         AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
541     };
542     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
543     return 0;
544 }
545
546 static const AVFilterPad avfilter_vsrc_testsrc_outputs[] = {
547     {
548         .name          = "default",
549         .type          = AVMEDIA_TYPE_VIDEO,
550         .request_frame = request_frame,
551         .config_props  = config_props,
552     },
553     { NULL }
554 };
555
556 AVFilter avfilter_vsrc_testsrc = {
557     .name          = "testsrc",
558     .description   = NULL_IF_CONFIG_SMALL("Generate test pattern."),
559     .priv_size     = sizeof(TestSourceContext),
560     .priv_class    = &testsrc_class,
561     .init          = test_init,
562     .uninit        = uninit,
563
564     .query_formats = test_query_formats,
565
566     .inputs    = NULL,
567     .outputs   = avfilter_vsrc_testsrc_outputs,
568 };
569
570 #endif /* CONFIG_TESTSRC_FILTER */
571
572 #if CONFIG_RGBTESTSRC_FILTER
573
574 #define rgbtestsrc_options options
575 AVFILTER_DEFINE_CLASS(rgbtestsrc);
576
577 #define R 0
578 #define G 1
579 #define B 2
580 #define A 3
581
582 static void rgbtest_put_pixel(uint8_t *dst, int dst_linesize,
583                               int x, int y, int r, int g, int b, enum AVPixelFormat fmt,
584                               uint8_t rgba_map[4])
585 {
586     int32_t v;
587     uint8_t *p;
588
589     switch (fmt) {
590     case AV_PIX_FMT_BGR444: ((uint16_t*)(dst + y*dst_linesize))[x] = ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4); break;
591     case AV_PIX_FMT_RGB444: ((uint16_t*)(dst + y*dst_linesize))[x] = ((b >> 4) << 8) | ((g >> 4) << 4) | (r >> 4); break;
592     case AV_PIX_FMT_BGR555: ((uint16_t*)(dst + y*dst_linesize))[x] = ((r>>3)<<10) | ((g>>3)<<5) | (b>>3); break;
593     case AV_PIX_FMT_RGB555: ((uint16_t*)(dst + y*dst_linesize))[x] = ((b>>3)<<10) | ((g>>3)<<5) | (r>>3); break;
594     case AV_PIX_FMT_BGR565: ((uint16_t*)(dst + y*dst_linesize))[x] = ((r>>3)<<11) | ((g>>2)<<5) | (b>>3); break;
595     case AV_PIX_FMT_RGB565: ((uint16_t*)(dst + y*dst_linesize))[x] = ((b>>3)<<11) | ((g>>2)<<5) | (r>>3); break;
596     case AV_PIX_FMT_RGB24:
597     case AV_PIX_FMT_BGR24:
598         v = (r << (rgba_map[R]*8)) + (g << (rgba_map[G]*8)) + (b << (rgba_map[B]*8));
599         p = dst + 3*x + y*dst_linesize;
600         AV_WL24(p, v);
601         break;
602     case AV_PIX_FMT_RGBA:
603     case AV_PIX_FMT_BGRA:
604     case AV_PIX_FMT_ARGB:
605     case AV_PIX_FMT_ABGR:
606         v = (r << (rgba_map[R]*8)) + (g << (rgba_map[G]*8)) + (b << (rgba_map[B]*8)) + (255 << (rgba_map[A]*8));
607         p = dst + 4*x + y*dst_linesize;
608         AV_WL32(p, v);
609         break;
610     }
611 }
612
613 static void rgbtest_fill_picture(AVFilterContext *ctx, AVFrame *frame)
614 {
615     TestSourceContext *test = ctx->priv;
616     int x, y, w = frame->width, h = frame->height;
617
618     for (y = 0; y < h; y++) {
619          for (x = 0; x < w; x++) {
620              int c = 256*x/w;
621              int r = 0, g = 0, b = 0;
622
623              if      (3*y < h  ) r = c;
624              else if (3*y < 2*h) g = c;
625              else                b = c;
626
627              rgbtest_put_pixel(frame->data[0], frame->linesize[0], x, y, r, g, b,
628                                ctx->outputs[0]->format, test->rgba_map);
629          }
630      }
631 }
632
633 static av_cold int rgbtest_init(AVFilterContext *ctx)
634 {
635     TestSourceContext *test = ctx->priv;
636
637     test->draw_once = 1;
638     test->fill_picture_fn = rgbtest_fill_picture;
639     return init(ctx);
640 }
641
642 static int rgbtest_query_formats(AVFilterContext *ctx)
643 {
644     static const enum AVPixelFormat pix_fmts[] = {
645         AV_PIX_FMT_RGBA, AV_PIX_FMT_ARGB, AV_PIX_FMT_BGRA, AV_PIX_FMT_ABGR,
646         AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24,
647         AV_PIX_FMT_RGB444, AV_PIX_FMT_BGR444,
648         AV_PIX_FMT_RGB565, AV_PIX_FMT_BGR565,
649         AV_PIX_FMT_RGB555, AV_PIX_FMT_BGR555,
650         AV_PIX_FMT_NONE
651     };
652     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
653     return 0;
654 }
655
656 static int rgbtest_config_props(AVFilterLink *outlink)
657 {
658     TestSourceContext *test = outlink->src->priv;
659
660     ff_fill_rgba_map(test->rgba_map, outlink->format);
661     return config_props(outlink);
662 }
663
664 static const AVFilterPad avfilter_vsrc_rgbtestsrc_outputs[] = {
665     {
666         .name          = "default",
667         .type          = AVMEDIA_TYPE_VIDEO,
668         .request_frame = request_frame,
669         .config_props  = rgbtest_config_props,
670     },
671     { NULL }
672 };
673
674 AVFilter avfilter_vsrc_rgbtestsrc = {
675     .name          = "rgbtestsrc",
676     .description   = NULL_IF_CONFIG_SMALL("Generate RGB test pattern."),
677     .priv_size     = sizeof(TestSourceContext),
678     .priv_class    = &rgbtestsrc_class,
679     .init          = rgbtest_init,
680     .uninit        = uninit,
681
682     .query_formats = rgbtest_query_formats,
683
684     .inputs    = NULL,
685
686     .outputs   = avfilter_vsrc_rgbtestsrc_outputs,
687 };
688
689 #endif /* CONFIG_RGBTESTSRC_FILTER */
690
691 #if CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER
692
693 static const uint8_t rainbow[7][4] = {
694     { 191, 191, 191, 255 },     /* gray */
695     { 191, 191,   0, 255 },     /* yellow */
696     {   0, 191, 191, 255 },     /* cyan */
697     {   0, 191,   0, 255 },     /* green */
698     { 191,   0, 191, 255 },     /* magenta */
699     { 191,   0,   0, 255 },     /* red */
700     {   0,   0, 191, 255 },     /* blue */
701 };
702
703 static const uint8_t wobnair[7][4] = {
704     {   0,   0, 191, 255 },     /* blue */
705     {  19,  19,  19, 255 },     /* 7.5% intensity black */
706     { 191,   0, 191, 255 },     /* magenta */
707     {  19,  19,  19, 255 },     /* 7.5% intensity black */
708     {   0, 191, 191, 255 },     /* cyan */
709     {  19,  19,  19, 255 },     /* 7.5% intensity black */
710     { 191, 191, 191, 255 },     /* gray */
711 };
712
713 static const uint8_t white[4] = { 255, 255, 255, 255 };
714 static const uint8_t black[4] = {  19,  19,  19, 255 }; /* 7.5% intensity black */
715
716 /* pluge pulses */
717 static const uint8_t neg4ire[4] = {   9,   9,   9, 255 }; /*  3.5% intensity black */
718 static const uint8_t pos4ire[4] = {  29,  29,  29, 255 }; /* 11.5% intensity black */
719
720 /* fudged Q/-I */
721 static const uint8_t i_pixel[4] = {   0,  68, 130, 255 };
722 static const uint8_t q_pixel[4] = {  67,   0, 130, 255 };
723
724 static const uint8_t gray40[4] = { 102, 102, 102, 255 };
725 static const uint8_t gray15[4] = {  38,  38,  38, 255 };
726 static const uint8_t   cyan[4] = {   0, 255, 255, 255 };
727 static const uint8_t yellow[4] = { 255, 255,   0, 255 };
728 static const uint8_t   blue[4] = {   0,   0, 255, 255 };
729 static const uint8_t    red[4] = { 255,   0,   0, 255 };
730 static const uint8_t black0[4] = {   5,   5,   5, 255 };
731 static const uint8_t black2[4] = {  10,  10,  10, 255 };
732 static const uint8_t black4[4] = {  15,  15,  15, 255 };
733 static const uint8_t   neg2[4] = {   0,   0,   0, 255 };
734
735 static void inline draw_bar(TestSourceContext *test, const uint8_t *color,
736                             unsigned x, unsigned y, unsigned w, unsigned h,
737                             AVFrame *frame)
738 {
739     FFDrawColor draw_color;
740
741     x = FFMIN(x, test->w - 1);
742     y = FFMIN(y, test->h - 1);
743     w = FFMIN(w, test->w - x);
744     h = FFMIN(h, test->h - y);
745
746     av_assert0(x + w <= test->w);
747     av_assert0(y + h <= test->h);
748
749     ff_draw_color(&test->draw, &draw_color, color);
750     ff_fill_rectangle(&test->draw, &draw_color,
751                       frame->data, frame->linesize, x, y, w, h);
752 }
753
754 static int smptebars_query_formats(AVFilterContext *ctx)
755 {
756     ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
757     return 0;
758 }
759
760 static int smptebars_config_props(AVFilterLink *outlink)
761 {
762     AVFilterContext *ctx = outlink->src;
763     TestSourceContext *test = ctx->priv;
764
765     ff_draw_init(&test->draw, outlink->format, 0);
766
767     return config_props(outlink);
768 }
769
770 static const AVFilterPad smptebars_outputs[] = {
771     {
772         .name          = "default",
773         .type          = AVMEDIA_TYPE_VIDEO,
774         .request_frame = request_frame,
775         .config_props  = smptebars_config_props,
776     },
777     { NULL }
778 };
779
780 #if CONFIG_SMPTEBARS_FILTER
781
782 #define smptebars_options options
783 AVFILTER_DEFINE_CLASS(smptebars);
784
785 static void smptebars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
786 {
787     TestSourceContext *test = ctx->priv;
788     int r_w, r_h, w_h, p_w, p_h, i, tmp, x = 0;
789     const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format);
790
791     r_w = FFALIGN((test->w + 6) / 7, 1 << pixdesc->log2_chroma_w);
792     r_h = FFALIGN(test->h * 2 / 3, 1 << pixdesc->log2_chroma_h);
793     w_h = FFALIGN(test->h * 3 / 4 - r_h,  1 << pixdesc->log2_chroma_h);
794     p_w = FFALIGN(r_w * 5 / 4, 1 << pixdesc->log2_chroma_w);
795     p_h = test->h - w_h - r_h;
796
797     for (i = 0; i < 7; i++) {
798         draw_bar(test, rainbow[i], x, 0,   r_w, r_h, picref);
799         draw_bar(test, wobnair[i], x, r_h, r_w, w_h, picref);
800         x += r_w;
801     }
802     x = 0;
803     draw_bar(test, i_pixel, x, r_h + w_h, p_w, p_h, picref);
804     x += p_w;
805     draw_bar(test, white, x, r_h + w_h, p_w, p_h, picref);
806     x += p_w;
807     draw_bar(test, q_pixel, x, r_h + w_h, p_w, p_h, picref);
808     x += p_w;
809     tmp = FFALIGN(5 * r_w - x,  1 << pixdesc->log2_chroma_w);
810     draw_bar(test, black, x, r_h + w_h, tmp, p_h, picref);
811     x += tmp;
812     tmp = FFALIGN(r_w / 3,  1 << pixdesc->log2_chroma_w);
813     draw_bar(test, neg4ire, x, r_h + w_h, tmp, p_h, picref);
814     x += tmp;
815     draw_bar(test, black, x, r_h + w_h, tmp, p_h, picref);
816     x += tmp;
817     draw_bar(test, pos4ire, x, r_h + w_h, tmp, p_h, picref);
818     x += tmp;
819     draw_bar(test, black, x, r_h + w_h, test->w - x, p_h, picref);
820 }
821
822 static av_cold int smptebars_init(AVFilterContext *ctx)
823 {
824     TestSourceContext *test = ctx->priv;
825
826     test->fill_picture_fn = smptebars_fill_picture;
827     test->draw_once = 1;
828     return init(ctx);
829 }
830
831 AVFilter avfilter_vsrc_smptebars = {
832     .name      = "smptebars",
833     .description = NULL_IF_CONFIG_SMALL("Generate SMPTE color bars."),
834     .priv_size = sizeof(TestSourceContext),
835     .init      = smptebars_init,
836     .uninit    = uninit,
837
838     .query_formats = smptebars_query_formats,
839     .inputs        = NULL,
840     .outputs       = smptebars_outputs,
841     .priv_class    = &smptebars_class,
842 };
843
844 #endif  /* CONFIG_SMPTEBARS_FILTER */
845
846 #if CONFIG_SMPTEHDBARS_FILTER
847
848 #define smptehdbars_options options
849 AVFILTER_DEFINE_CLASS(smptehdbars);
850
851 static void smptehdbars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
852 {
853     TestSourceContext *test = ctx->priv;
854     int d_w, r_w, r_h, l_w, i, tmp, x = 0, y = 0;
855     const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format);
856
857     d_w = FFALIGN(test->w / 8, 1 << pixdesc->log2_chroma_w);
858     r_h = FFALIGN(test->h * 7 / 12, 1 << pixdesc->log2_chroma_h);
859     draw_bar(test, gray40, x, 0, d_w, r_h, picref);
860     x += d_w;
861
862     r_w = FFALIGN((((test->w + 3) / 4) * 3) / 7, 1 << pixdesc->log2_chroma_w);
863     for (i = 0; i < 7; i++) {
864         draw_bar(test, rainbow[i], x, 0, r_w, r_h, picref);
865         x += r_w;
866     }
867     draw_bar(test, gray40, x, 0, test->w - x, r_h, picref);
868     y = r_h;
869     r_h = FFALIGN(test->h / 12, 1 << pixdesc->log2_chroma_h);
870     draw_bar(test, cyan, 0, y, d_w, r_h, picref);
871     x = d_w;
872     draw_bar(test, i_pixel, x, y, r_w, r_h, picref);
873     x += r_w;
874     tmp = r_w * 6;
875     draw_bar(test, rainbow[0], x, y, tmp, r_h, picref);
876     x += tmp;
877     l_w = x;
878     draw_bar(test, blue, x, y, test->w - x, r_h, picref);
879     y += r_h;
880     draw_bar(test, yellow, 0, y, d_w, r_h, picref);
881     x = d_w;
882     draw_bar(test, q_pixel, x, y, r_w, r_h, picref);
883     x += r_w;
884
885     for (i = 0; i < tmp; i += 1 << pixdesc->log2_chroma_w) {
886         uint8_t yramp[4] = {0};
887
888         yramp[0] =
889         yramp[1] =
890         yramp[2] = i * 255 / tmp;
891         yramp[3] = 255;
892
893         draw_bar(test, yramp, x, y, 1 << pixdesc->log2_chroma_w, r_h, picref);
894         x += 1 << pixdesc->log2_chroma_w;
895     }
896     draw_bar(test, red, x, y, test->w - x, r_h, picref);
897     y += r_h;
898     draw_bar(test, gray15, 0, y, d_w, test->h - y, picref);
899     x = d_w;
900     tmp = FFALIGN(r_w * 3 / 2, 1 << pixdesc->log2_chroma_w);
901     draw_bar(test, black0, x, y, tmp, test->h - y, picref);
902     x += tmp;
903     tmp = FFALIGN(r_w * 2, 1 << pixdesc->log2_chroma_w);
904     draw_bar(test, white, x, y, tmp, test->h - y, picref);
905     x += tmp;
906     tmp = FFALIGN(r_w * 5 / 6, 1 << pixdesc->log2_chroma_w);
907     draw_bar(test, black0, x, y, tmp, test->h - y, picref);
908     x += tmp;
909     tmp = FFALIGN(r_w / 3, 1 << pixdesc->log2_chroma_w);
910     draw_bar(test,   neg2, x, y, tmp, test->h - y, picref);
911     x += tmp;
912     draw_bar(test, black0, x, y, tmp, test->h - y, picref);
913     x += tmp;
914     draw_bar(test, black2, x, y, tmp, test->h - y, picref);
915     x += tmp;
916     draw_bar(test, black0, x, y, tmp, test->h - y, picref);
917     x += tmp;
918     draw_bar(test, black4, x, y, tmp, test->h - y, picref);
919     x += tmp;
920     r_w = l_w - x;
921     draw_bar(test, black0, x, y, r_w, test->h - y, picref);
922     x += r_w;
923     draw_bar(test, gray15, x, y, test->w - x, test->h - y, picref);
924 }
925
926 static av_cold int smptehdbars_init(AVFilterContext *ctx)
927 {
928     TestSourceContext *test = ctx->priv;
929
930     test->fill_picture_fn = smptehdbars_fill_picture;
931     test->draw_once = 1;
932     return init(ctx);
933 }
934
935 AVFilter avfilter_vsrc_smptehdbars = {
936     .name      = "smptehdbars",
937     .description = NULL_IF_CONFIG_SMALL("Generate SMPTE HD color bars."),
938     .priv_size = sizeof(TestSourceContext),
939     .init      = smptehdbars_init,
940     .uninit    = uninit,
941
942     .query_formats = smptebars_query_formats,
943     .inputs        = NULL,
944     .outputs       = smptebars_outputs,
945     .priv_class    = &smptehdbars_class,
946 };
947
948 #endif  /* CONFIG_SMPTEHDBARS_FILTER */
949 #endif  /* CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER */