2 * Copyright (c) 2007 Nicolas George <nicolas.george@normalesup.org>
3 * Copyright (c) 2011 Stefano Sabatini
4 * Copyright (c) 2012 Paul B Mahol
6 * This file is part of FFmpeg.
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.
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.
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
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
30 * rgbtestsrc is ported from MPlayer libmpcodecs/vf_rgbtest.c by
31 * Michael Niedermayer.
33 * smptebars and smptehdbars are by Paul B Mahol.
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"
45 #include "drawutils.h"
50 typedef struct TestSourceContext
{
53 unsigned int nb_frame
;
54 AVRational time_base
, frame_rate
;
56 int64_t duration
; ///< duration expressed in microseconds
57 AVRational sar
; ///< sample aspect ratio
58 int draw_once
; ///< draw only the first frame, always put out the same picture
59 int draw_once_reset
; ///< draw only the first frame or in case of reset
60 AVFrame
*picref
; ///< cached reference containing the painted picture
62 void (* fill_picture_fn
)(AVFilterContext
*ctx
, AVFrame
*frame
);
64 /* only used by testsrc */
67 /* only used by color */
70 uint8_t color_rgba
[4];
72 /* only used by rgbtest */
75 /* only used by haldclut */
79 #define OFFSET(x) offsetof(TestSourceContext, x)
80 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
82 #define SIZE_OPTIONS \
83 { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
84 { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\
86 #define COMMON_OPTIONS_NOSIZE \
87 { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
88 { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
89 { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\
90 { "d", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\
91 { "sar", "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl= 1}, 0, INT_MAX, FLAGS },
93 #define COMMON_OPTIONS SIZE_OPTIONS COMMON_OPTIONS_NOSIZE
95 static const AVOption options
[] = {
100 static av_cold
int init(AVFilterContext
*ctx
)
102 TestSourceContext
*test
= ctx
->priv
;
104 test
->time_base
= av_inv_q(test
->frame_rate
);
108 av_log(ctx
, AV_LOG_VERBOSE
, "size:%dx%d rate:%d/%d duration:%f sar:%d/%d\n",
109 test
->w
, test
->h
, test
->frame_rate
.num
, test
->frame_rate
.den
,
110 test
->duration
< 0 ? -1 : (double)test
->duration
/1000000,
111 test
->sar
.num
, test
->sar
.den
);
115 static av_cold
void uninit(AVFilterContext
*ctx
)
117 TestSourceContext
*test
= ctx
->priv
;
119 av_frame_free(&test
->picref
);
122 static int config_props(AVFilterLink
*outlink
)
124 TestSourceContext
*test
= outlink
->src
->priv
;
126 outlink
->w
= test
->w
;
127 outlink
->h
= test
->h
;
128 outlink
->sample_aspect_ratio
= test
->sar
;
129 outlink
->frame_rate
= test
->frame_rate
;
130 outlink
->time_base
= test
->time_base
;
135 static int request_frame(AVFilterLink
*outlink
)
137 TestSourceContext
*test
= outlink
->src
->priv
;
140 if (test
->duration
>= 0 &&
141 av_rescale_q(test
->pts
, test
->time_base
, AV_TIME_BASE_Q
) >= test
->duration
)
144 if (test
->draw_once
) {
145 if (test
->draw_once_reset
) {
146 av_frame_free(&test
->picref
);
147 test
->draw_once_reset
= 0;
151 ff_get_video_buffer(outlink
, test
->w
, test
->h
);
153 return AVERROR(ENOMEM
);
154 test
->fill_picture_fn(outlink
->src
, test
->picref
);
156 frame
= av_frame_clone(test
->picref
);
158 frame
= ff_get_video_buffer(outlink
, test
->w
, test
->h
);
161 return AVERROR(ENOMEM
);
162 frame
->pts
= test
->pts
;
163 frame
->key_frame
= 1;
164 frame
->interlaced_frame
= 0;
165 frame
->pict_type
= AV_PICTURE_TYPE_I
;
166 frame
->sample_aspect_ratio
= test
->sar
;
167 if (!test
->draw_once
)
168 test
->fill_picture_fn(outlink
->src
, frame
);
173 return ff_filter_frame(outlink
, frame
);
176 #if CONFIG_COLOR_FILTER
178 static const AVOption color_options
[] = {
179 { "color", "set color", OFFSET(color_rgba
), AV_OPT_TYPE_COLOR
, {.str
= "black"}, CHAR_MIN
, CHAR_MAX
, FLAGS
},
180 { "c", "set color", OFFSET(color_rgba
), AV_OPT_TYPE_COLOR
, {.str
= "black"}, CHAR_MIN
, CHAR_MAX
, FLAGS
},
185 AVFILTER_DEFINE_CLASS(color
);
187 static void color_fill_picture(AVFilterContext
*ctx
, AVFrame
*picref
)
189 TestSourceContext
*test
= ctx
->priv
;
190 ff_fill_rectangle(&test
->draw
, &test
->color
,
191 picref
->data
, picref
->linesize
,
192 0, 0, test
->w
, test
->h
);
195 static av_cold
int color_init(AVFilterContext
*ctx
)
197 TestSourceContext
*test
= ctx
->priv
;
198 test
->fill_picture_fn
= color_fill_picture
;
203 static int color_query_formats(AVFilterContext
*ctx
)
205 ff_set_common_formats(ctx
, ff_draw_supported_pixel_formats(0));
209 static int color_config_props(AVFilterLink
*inlink
)
211 AVFilterContext
*ctx
= inlink
->src
;
212 TestSourceContext
*test
= ctx
->priv
;
215 ff_draw_init(&test
->draw
, inlink
->format
, 0);
216 ff_draw_color(&test
->draw
, &test
->color
, test
->color_rgba
);
218 test
->w
= ff_draw_round_to_sub(&test
->draw
, 0, -1, test
->w
);
219 test
->h
= ff_draw_round_to_sub(&test
->draw
, 1, -1, test
->h
);
220 if (av_image_check_size(test
->w
, test
->h
, 0, ctx
) < 0)
221 return AVERROR(EINVAL
);
223 if ((ret
= config_props(inlink
)) < 0)
229 static int color_process_command(AVFilterContext
*ctx
, const char *cmd
, const char *args
,
230 char *res
, int res_len
, int flags
)
232 TestSourceContext
*test
= ctx
->priv
;
235 if (!strcmp(cmd
, "color") || !strcmp(cmd
, "c")) {
236 uint8_t color_rgba
[4];
238 ret
= av_parse_color(color_rgba
, args
, -1, ctx
);
242 memcpy(test
->color_rgba
, color_rgba
, sizeof(color_rgba
));
243 ff_draw_color(&test
->draw
, &test
->color
, test
->color_rgba
);
244 test
->draw_once_reset
= 1;
248 return AVERROR(ENOSYS
);
251 static const AVFilterPad color_outputs
[] = {
254 .type
= AVMEDIA_TYPE_VIDEO
,
255 .request_frame
= request_frame
,
256 .config_props
= color_config_props
,
261 AVFilter ff_vsrc_color
= {
263 .description
= NULL_IF_CONFIG_SMALL("Provide an uniformly colored input."),
264 .priv_class
= &color_class
,
265 .priv_size
= sizeof(TestSourceContext
),
268 .query_formats
= color_query_formats
,
270 .outputs
= color_outputs
,
271 .process_command
= color_process_command
,
274 #endif /* CONFIG_COLOR_FILTER */
276 #if CONFIG_HALDCLUTSRC_FILTER
278 static const AVOption haldclutsrc_options
[] = {
279 { "level", "set level", OFFSET(level
), AV_OPT_TYPE_INT
, {.i64
= 6}, 2, 8, FLAGS
},
280 COMMON_OPTIONS_NOSIZE
284 AVFILTER_DEFINE_CLASS(haldclutsrc
);
286 static void haldclutsrc_fill_picture(AVFilterContext
*ctx
, AVFrame
*frame
)
288 int i
, j
, k
, x
= 0, y
= 0, is16bit
= 0, step
;
290 const TestSourceContext
*hc
= ctx
->priv
;
291 int level
= hc
->level
;
293 const int w
= frame
->width
;
294 const int h
= frame
->height
;
295 const uint8_t *data
= frame
->data
[0];
296 const int linesize
= frame
->linesize
[0];
297 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(frame
->format
);
300 av_assert0(w
== h
&& w
== level
*level
*level
);
302 ff_fill_rgba_map(rgba_map
, frame
->format
);
304 switch (frame
->format
) {
305 case AV_PIX_FMT_RGB48
:
306 case AV_PIX_FMT_BGR48
:
307 case AV_PIX_FMT_RGBA64
:
308 case AV_PIX_FMT_BGRA64
:
312 case AV_PIX_FMT_RGBA
:
313 case AV_PIX_FMT_BGRA
:
314 case AV_PIX_FMT_ARGB
:
315 case AV_PIX_FMT_ABGR
:
320 step
= av_get_padded_bits_per_pixel(desc
) >> (3 + is16bit
);
321 scale
= ((float)(1 << (8*(is16bit
+1))) - 1) / (level
*level
- 1);
323 #define LOAD_CLUT(nbits) do { \
324 uint##nbits##_t *dst = ((uint##nbits##_t *)(data + y*linesize)) + x*step; \
325 dst[rgba_map[0]] = av_clip_uint##nbits(i * scale); \
326 dst[rgba_map[1]] = av_clip_uint##nbits(j * scale); \
327 dst[rgba_map[2]] = av_clip_uint##nbits(k * scale); \
329 dst[rgba_map[3]] = alpha; \
333 for (k
= 0; k
< level
; k
++) {
334 for (j
= 0; j
< level
; j
++) {
335 for (i
= 0; i
< level
; i
++) {
349 static av_cold
int haldclutsrc_init(AVFilterContext
*ctx
)
351 TestSourceContext
*hc
= ctx
->priv
;
352 hc
->fill_picture_fn
= haldclutsrc_fill_picture
;
357 static int haldclutsrc_query_formats(AVFilterContext
*ctx
)
359 static const enum AVPixelFormat pix_fmts
[] = {
360 AV_PIX_FMT_RGB24
, AV_PIX_FMT_BGR24
,
361 AV_PIX_FMT_RGBA
, AV_PIX_FMT_BGRA
,
362 AV_PIX_FMT_ARGB
, AV_PIX_FMT_ABGR
,
363 AV_PIX_FMT_0RGB
, AV_PIX_FMT_0BGR
,
364 AV_PIX_FMT_RGB0
, AV_PIX_FMT_BGR0
,
365 AV_PIX_FMT_RGB48
, AV_PIX_FMT_BGR48
,
366 AV_PIX_FMT_RGBA64
, AV_PIX_FMT_BGRA64
,
369 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
373 static int haldclutsrc_config_props(AVFilterLink
*outlink
)
375 AVFilterContext
*ctx
= outlink
->src
;
376 TestSourceContext
*hc
= ctx
->priv
;
378 hc
->w
= hc
->h
= hc
->level
* hc
->level
* hc
->level
;
379 return config_props(outlink
);
382 static const AVFilterPad haldclutsrc_outputs
[] = {
385 .type
= AVMEDIA_TYPE_VIDEO
,
386 .request_frame
= request_frame
,
387 .config_props
= haldclutsrc_config_props
,
392 AVFilter ff_vsrc_haldclutsrc
= {
393 .name
= "haldclutsrc",
394 .description
= NULL_IF_CONFIG_SMALL("Provide an identity Hald CLUT."),
395 .priv_class
= &haldclutsrc_class
,
396 .priv_size
= sizeof(TestSourceContext
),
397 .init
= haldclutsrc_init
,
399 .query_formats
= haldclutsrc_query_formats
,
401 .outputs
= haldclutsrc_outputs
,
403 #endif /* CONFIG_HALDCLUTSRC_FILTER */
405 #if CONFIG_NULLSRC_FILTER
407 #define nullsrc_options options
408 AVFILTER_DEFINE_CLASS(nullsrc
);
410 static void nullsrc_fill_picture(AVFilterContext
*ctx
, AVFrame
*picref
) { }
412 static av_cold
int nullsrc_init(AVFilterContext
*ctx
)
414 TestSourceContext
*test
= ctx
->priv
;
416 test
->fill_picture_fn
= nullsrc_fill_picture
;
420 static const AVFilterPad nullsrc_outputs
[] = {
423 .type
= AVMEDIA_TYPE_VIDEO
,
424 .request_frame
= request_frame
,
425 .config_props
= config_props
,
430 AVFilter ff_vsrc_nullsrc
= {
432 .description
= NULL_IF_CONFIG_SMALL("Null video source, return unprocessed video frames."),
433 .init
= nullsrc_init
,
435 .priv_size
= sizeof(TestSourceContext
),
436 .priv_class
= &nullsrc_class
,
438 .outputs
= nullsrc_outputs
,
441 #endif /* CONFIG_NULLSRC_FILTER */
443 #if CONFIG_TESTSRC_FILTER
445 static const AVOption testsrc_options
[] = {
447 { "decimals", "set number of decimals to show", OFFSET(nb_decimals
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 17, FLAGS
},
448 { "n", "set number of decimals to show", OFFSET(nb_decimals
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 17, FLAGS
},
452 AVFILTER_DEFINE_CLASS(testsrc
);
455 * Fill a rectangle with value val.
457 * @param val the RGB value to set
458 * @param dst pointer to the destination buffer to fill
459 * @param dst_linesize linesize of destination
460 * @param segment_width width of the segment
461 * @param x horizontal coordinate where to draw the rectangle in the destination buffer
462 * @param y horizontal coordinate where to draw the rectangle in the destination buffer
463 * @param w width of the rectangle to draw, expressed as a number of segment_width units
464 * @param h height of the rectangle to draw, expressed as a number of segment_width units
466 static void draw_rectangle(unsigned val
, uint8_t *dst
, int dst_linesize
, int segment_width
,
467 int x
, int y
, int w
, int h
)
472 dst
+= segment_width
* (step
* x
+ y
* dst_linesize
);
473 w
*= segment_width
* step
;
475 for (i
= 0; i
< h
; i
++) {
481 static void draw_digit(int digit
, uint8_t *dst
, int dst_linesize
,
487 #define LEFT_TOP_VBAR 8
488 #define LEFT_BOT_VBAR 16
489 #define RIGHT_TOP_VBAR 32
490 #define RIGHT_BOT_VBAR 64
494 { 1, 0, 5, 1 }, /* TOP_HBAR */
495 { 1, 6, 5, 1 }, /* MID_HBAR */
496 { 1, 12, 5, 1 }, /* BOT_HBAR */
497 { 0, 1, 1, 5 }, /* LEFT_TOP_VBAR */
498 { 0, 7, 1, 5 }, /* LEFT_BOT_VBAR */
499 { 6, 1, 1, 5 }, /* RIGHT_TOP_VBAR */
500 { 6, 7, 1, 5 } /* RIGHT_BOT_VBAR */
502 static const unsigned char masks
[10] = {
503 /* 0 */ TOP_HBAR
|BOT_HBAR
|LEFT_TOP_VBAR
|LEFT_BOT_VBAR
|RIGHT_TOP_VBAR
|RIGHT_BOT_VBAR
,
504 /* 1 */ RIGHT_TOP_VBAR
|RIGHT_BOT_VBAR
,
505 /* 2 */ TOP_HBAR
|MID_HBAR
|BOT_HBAR
|LEFT_BOT_VBAR
|RIGHT_TOP_VBAR
,
506 /* 3 */ TOP_HBAR
|MID_HBAR
|BOT_HBAR
|RIGHT_TOP_VBAR
|RIGHT_BOT_VBAR
,
507 /* 4 */ MID_HBAR
|LEFT_TOP_VBAR
|RIGHT_TOP_VBAR
|RIGHT_BOT_VBAR
,
508 /* 5 */ TOP_HBAR
|BOT_HBAR
|MID_HBAR
|LEFT_TOP_VBAR
|RIGHT_BOT_VBAR
,
509 /* 6 */ TOP_HBAR
|BOT_HBAR
|MID_HBAR
|LEFT_TOP_VBAR
|LEFT_BOT_VBAR
|RIGHT_BOT_VBAR
,
510 /* 7 */ TOP_HBAR
|RIGHT_TOP_VBAR
|RIGHT_BOT_VBAR
,
511 /* 8 */ TOP_HBAR
|BOT_HBAR
|MID_HBAR
|LEFT_TOP_VBAR
|LEFT_BOT_VBAR
|RIGHT_TOP_VBAR
|RIGHT_BOT_VBAR
,
512 /* 9 */ TOP_HBAR
|BOT_HBAR
|MID_HBAR
|LEFT_TOP_VBAR
|RIGHT_TOP_VBAR
|RIGHT_BOT_VBAR
,
514 unsigned mask
= masks
[digit
];
517 draw_rectangle(0, dst
, dst_linesize
, segment_width
, 0, 0, 8, 13);
518 for (i
= 0; i
< FF_ARRAY_ELEMS(segments
); i
++)
520 draw_rectangle(255, dst
, dst_linesize
, segment_width
,
521 segments
[i
].x
, segments
[i
].y
, segments
[i
].w
, segments
[i
].h
);
524 #define GRADIENT_SIZE (6 * 256)
526 static void test_fill_picture(AVFilterContext
*ctx
, AVFrame
*frame
)
528 TestSourceContext
*test
= ctx
->priv
;
531 int color
, color_rest
;
535 int dquad_x
, dquad_y
;
536 int grad
, dgrad
, rgrad
, drgrad
;
540 uint8_t *data
= frame
->data
[0];
541 int width
= frame
->width
;
542 int height
= frame
->height
;
544 /* draw colored bars and circle */
545 radius
= (width
+ height
) / 4;
546 quad0
= width
* width
/ 4 + height
* height
/ 4 - radius
* radius
;
547 dquad_y
= 1 - height
;
549 for (y
= 0; y
< height
; y
++) {
555 for (x
= 0; x
< width
; x
++) {
561 *(p
++) = icolor
& 1 ? 255 : 0;
562 *(p
++) = icolor
& 2 ? 255 : 0;
563 *(p
++) = icolor
& 4 ? 255 : 0;
565 if (color_rest
>= width
) {
572 p0
+= frame
->linesize
[0];
575 /* draw sliding color line */
576 p0
= p
= data
+ frame
->linesize
[0] * (height
* 3/4);
577 grad
= (256 * test
->nb_frame
* test
->time_base
.num
/ test
->time_base
.den
) %
580 dgrad
= GRADIENT_SIZE
/ width
;
581 drgrad
= GRADIENT_SIZE
% width
;
582 for (x
= 0; x
< width
; x
++) {
584 grad
< 256 || grad
>= 5 * 256 ? 255 :
585 grad
>= 2 * 256 && grad
< 4 * 256 ? 0 :
586 grad
< 2 * 256 ? 2 * 256 - 1 - grad
: grad
- 4 * 256;
588 grad
>= 4 * 256 ? 0 :
589 grad
>= 1 * 256 && grad
< 3 * 256 ? 255 :
590 grad
< 1 * 256 ? grad
: 4 * 256 - 1 - grad
;
593 grad
>= 3 * 256 && grad
< 5 * 256 ? 255 :
594 grad
< 3 * 256 ? grad
- 2 * 256 : 6 * 256 - 1 - grad
;
597 if (rgrad
>= GRADIENT_SIZE
) {
599 rgrad
-= GRADIENT_SIZE
;
601 if (grad
>= GRADIENT_SIZE
)
602 grad
-= GRADIENT_SIZE
;
605 for (y
= height
/ 8; y
> 0; y
--) {
606 memcpy(p
+frame
->linesize
[0], p
, 3 * width
);
607 p
+= frame
->linesize
[0];
611 seg_size
= width
/ 80;
612 if (seg_size
>= 1 && height
>= 13 * seg_size
) {
613 int64_t p10decimals
= 1;
614 double time
= av_q2d(test
->time_base
) * test
->nb_frame
*
615 pow(10, test
->nb_decimals
);
619 for (x
= 0; x
< test
->nb_decimals
; x
++)
622 second
= av_rescale_rnd(test
->nb_frame
* test
->time_base
.num
, p10decimals
, test
->time_base
.den
, AV_ROUND_ZERO
);
623 x
= width
- (width
- seg_size
* 64) / 2;
624 y
= (height
- seg_size
* 13) / 2;
625 p
= data
+ (x
*3 + y
* frame
->linesize
[0]);
626 for (i
= 0; i
< 8; i
++) {
627 p
-= 3 * 8 * seg_size
;
628 draw_digit(second
% 10, p
, frame
->linesize
[0], seg_size
);
636 static av_cold
int test_init(AVFilterContext
*ctx
)
638 TestSourceContext
*test
= ctx
->priv
;
640 test
->fill_picture_fn
= test_fill_picture
;
644 static int test_query_formats(AVFilterContext
*ctx
)
646 static const enum AVPixelFormat pix_fmts
[] = {
647 AV_PIX_FMT_RGB24
, AV_PIX_FMT_NONE
649 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
653 static const AVFilterPad avfilter_vsrc_testsrc_outputs
[] = {
656 .type
= AVMEDIA_TYPE_VIDEO
,
657 .request_frame
= request_frame
,
658 .config_props
= config_props
,
663 AVFilter ff_vsrc_testsrc
= {
665 .description
= NULL_IF_CONFIG_SMALL("Generate test pattern."),
666 .priv_size
= sizeof(TestSourceContext
),
667 .priv_class
= &testsrc_class
,
670 .query_formats
= test_query_formats
,
672 .outputs
= avfilter_vsrc_testsrc_outputs
,
675 #endif /* CONFIG_TESTSRC_FILTER */
677 #if CONFIG_RGBTESTSRC_FILTER
679 #define rgbtestsrc_options options
680 AVFILTER_DEFINE_CLASS(rgbtestsrc
);
687 static void rgbtest_put_pixel(uint8_t *dst
, int dst_linesize
,
688 int x
, int y
, int r
, int g
, int b
, enum AVPixelFormat fmt
,
695 case AV_PIX_FMT_BGR444
: ((uint16_t*)(dst
+ y
*dst_linesize
))[x
] = ((r
>> 4) << 8) | ((g
>> 4) << 4) | (b
>> 4); break;
696 case AV_PIX_FMT_RGB444
: ((uint16_t*)(dst
+ y
*dst_linesize
))[x
] = ((b
>> 4) << 8) | ((g
>> 4) << 4) | (r
>> 4); break;
697 case AV_PIX_FMT_BGR555
: ((uint16_t*)(dst
+ y
*dst_linesize
))[x
] = ((r
>>3)<<10) | ((g
>>3)<<5) | (b
>>3); break;
698 case AV_PIX_FMT_RGB555
: ((uint16_t*)(dst
+ y
*dst_linesize
))[x
] = ((b
>>3)<<10) | ((g
>>3)<<5) | (r
>>3); break;
699 case AV_PIX_FMT_BGR565
: ((uint16_t*)(dst
+ y
*dst_linesize
))[x
] = ((r
>>3)<<11) | ((g
>>2)<<5) | (b
>>3); break;
700 case AV_PIX_FMT_RGB565
: ((uint16_t*)(dst
+ y
*dst_linesize
))[x
] = ((b
>>3)<<11) | ((g
>>2)<<5) | (r
>>3); break;
701 case AV_PIX_FMT_RGB24
:
702 case AV_PIX_FMT_BGR24
:
703 v
= (r
<< (rgba_map
[R
]*8)) + (g
<< (rgba_map
[G
]*8)) + (b
<< (rgba_map
[B
]*8));
704 p
= dst
+ 3*x
+ y
*dst_linesize
;
707 case AV_PIX_FMT_RGBA
:
708 case AV_PIX_FMT_BGRA
:
709 case AV_PIX_FMT_ARGB
:
710 case AV_PIX_FMT_ABGR
:
711 v
= (r
<< (rgba_map
[R
]*8)) + (g
<< (rgba_map
[G
]*8)) + (b
<< (rgba_map
[B
]*8)) + (255 << (rgba_map
[A
]*8));
712 p
= dst
+ 4*x
+ y
*dst_linesize
;
718 static void rgbtest_fill_picture(AVFilterContext
*ctx
, AVFrame
*frame
)
720 TestSourceContext
*test
= ctx
->priv
;
721 int x
, y
, w
= frame
->width
, h
= frame
->height
;
723 for (y
= 0; y
< h
; y
++) {
724 for (x
= 0; x
< w
; x
++) {
726 int r
= 0, g
= 0, b
= 0;
729 else if (3*y
< 2*h
) g
= c
;
732 rgbtest_put_pixel(frame
->data
[0], frame
->linesize
[0], x
, y
, r
, g
, b
,
733 ctx
->outputs
[0]->format
, test
->rgba_map
);
738 static av_cold
int rgbtest_init(AVFilterContext
*ctx
)
740 TestSourceContext
*test
= ctx
->priv
;
743 test
->fill_picture_fn
= rgbtest_fill_picture
;
747 static int rgbtest_query_formats(AVFilterContext
*ctx
)
749 static const enum AVPixelFormat pix_fmts
[] = {
750 AV_PIX_FMT_RGBA
, AV_PIX_FMT_ARGB
, AV_PIX_FMT_BGRA
, AV_PIX_FMT_ABGR
,
751 AV_PIX_FMT_BGR24
, AV_PIX_FMT_RGB24
,
752 AV_PIX_FMT_RGB444
, AV_PIX_FMT_BGR444
,
753 AV_PIX_FMT_RGB565
, AV_PIX_FMT_BGR565
,
754 AV_PIX_FMT_RGB555
, AV_PIX_FMT_BGR555
,
757 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
761 static int rgbtest_config_props(AVFilterLink
*outlink
)
763 TestSourceContext
*test
= outlink
->src
->priv
;
765 ff_fill_rgba_map(test
->rgba_map
, outlink
->format
);
766 return config_props(outlink
);
769 static const AVFilterPad avfilter_vsrc_rgbtestsrc_outputs
[] = {
772 .type
= AVMEDIA_TYPE_VIDEO
,
773 .request_frame
= request_frame
,
774 .config_props
= rgbtest_config_props
,
779 AVFilter ff_vsrc_rgbtestsrc
= {
780 .name
= "rgbtestsrc",
781 .description
= NULL_IF_CONFIG_SMALL("Generate RGB test pattern."),
782 .priv_size
= sizeof(TestSourceContext
),
783 .priv_class
= &rgbtestsrc_class
,
784 .init
= rgbtest_init
,
786 .query_formats
= rgbtest_query_formats
,
788 .outputs
= avfilter_vsrc_rgbtestsrc_outputs
,
791 #endif /* CONFIG_RGBTESTSRC_FILTER */
793 #if CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER
795 static const uint8_t rainbow
[7][4] = {
796 { 180, 128, 128, 255 }, /* gray */
797 { 168, 44, 136, 255 }, /* yellow */
798 { 145, 147, 44, 255 }, /* cyan */
799 { 133, 63, 52, 255 }, /* green */
800 { 63, 193, 204, 255 }, /* magenta */
801 { 51, 109, 212, 255 }, /* red */
802 { 28, 212, 120, 255 }, /* blue */
805 static const uint8_t wobnair
[7][4] = {
806 { 32, 240, 118, 255 }, /* blue */
807 { 19, 128, 128, 255 }, /* 7.5% intensity black */
808 { 54, 184, 198, 255 }, /* magenta */
809 { 19, 128, 128, 255 }, /* 7.5% intensity black */
810 { 188, 154, 16, 255 }, /* cyan */
811 { 19, 128, 128, 255 }, /* 7.5% intensity black */
812 { 191, 128, 128, 255 }, /* gray */
815 static const uint8_t white
[4] = { 235, 128, 128, 255 };
816 static const uint8_t black
[4] = { 19, 128, 128, 255 }; /* 7.5% intensity black */
819 static const uint8_t neg4ire
[4] = { 9, 128, 128, 255 }; /* 3.5% intensity black */
820 static const uint8_t pos4ire
[4] = { 29, 128, 128, 255 }; /* 11.5% intensity black */
823 static const uint8_t i_pixel
[4] = { 61, 153, 99, 255 };
824 static const uint8_t q_pixel
[4] = { 35, 174, 152, 255 };
826 static const uint8_t gray40
[4] = { 104, 128, 128, 255 };
827 static const uint8_t gray15
[4] = { 49, 128, 128, 255 };
828 static const uint8_t cyan
[4] = { 188, 154, 16, 255 };
829 static const uint8_t yellow
[4] = { 219, 16, 138, 255 };
830 static const uint8_t blue
[4] = { 32, 240, 118, 255 };
831 static const uint8_t red
[4] = { 63, 102, 240, 255 };
832 static const uint8_t black0
[4] = { 16, 128, 128, 255 };
833 static const uint8_t black2
[4] = { 20, 128, 128, 255 };
834 static const uint8_t black4
[4] = { 25, 128, 128, 255 };
835 static const uint8_t neg2
[4] = { 12, 128, 128, 255 };
837 static void draw_bar(TestSourceContext
*test
, const uint8_t color
[4],
838 unsigned x
, unsigned y
, unsigned w
, unsigned h
,
841 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(frame
->format
);
845 x
= FFMIN(x
, test
->w
- 1);
846 y
= FFMIN(y
, test
->h
- 1);
847 w
= FFMIN(w
, test
->w
- x
);
848 h
= FFMIN(h
, test
->h
- y
);
850 av_assert0(x
+ w
<= test
->w
);
851 av_assert0(y
+ h
<= test
->h
);
853 for (plane
= 0; frame
->data
[plane
]; plane
++) {
854 const int c
= color
[plane
];
855 const int linesize
= frame
->linesize
[plane
];
856 int i
, px
, py
, pw
, ph
;
858 if (plane
== 1 || plane
== 2) {
859 px
= x
>> desc
->log2_chroma_w
;
860 pw
= w
>> desc
->log2_chroma_w
;
861 py
= y
>> desc
->log2_chroma_h
;
862 ph
= h
>> desc
->log2_chroma_h
;
870 p0
= p
= frame
->data
[plane
] + py
* linesize
+ px
;
873 for (i
= 1; i
< ph
; i
++, p
+= linesize
)
878 static int smptebars_query_formats(AVFilterContext
*ctx
)
880 static const enum AVPixelFormat pix_fmts
[] = {
881 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUV422P
,
882 AV_PIX_FMT_YUV440P
, AV_PIX_FMT_YUV444P
,
883 AV_PIX_FMT_YUV410P
, AV_PIX_FMT_YUV411P
,
886 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
890 static const AVFilterPad smptebars_outputs
[] = {
893 .type
= AVMEDIA_TYPE_VIDEO
,
894 .request_frame
= request_frame
,
895 .config_props
= config_props
,
900 #if CONFIG_SMPTEBARS_FILTER
902 #define smptebars_options options
903 AVFILTER_DEFINE_CLASS(smptebars
);
905 static void smptebars_fill_picture(AVFilterContext
*ctx
, AVFrame
*picref
)
907 TestSourceContext
*test
= ctx
->priv
;
908 int r_w
, r_h
, w_h
, p_w
, p_h
, i
, tmp
, x
= 0;
909 const AVPixFmtDescriptor
*pixdesc
= av_pix_fmt_desc_get(picref
->format
);
911 av_frame_set_colorspace(picref
, AVCOL_SPC_BT470BG
);
913 r_w
= FFALIGN((test
->w
+ 6) / 7, 1 << pixdesc
->log2_chroma_w
);
914 r_h
= FFALIGN(test
->h
* 2 / 3, 1 << pixdesc
->log2_chroma_h
);
915 w_h
= FFALIGN(test
->h
* 3 / 4 - r_h
, 1 << pixdesc
->log2_chroma_h
);
916 p_w
= FFALIGN(r_w
* 5 / 4, 1 << pixdesc
->log2_chroma_w
);
917 p_h
= test
->h
- w_h
- r_h
;
919 for (i
= 0; i
< 7; i
++) {
920 draw_bar(test
, rainbow
[i
], x
, 0, r_w
, r_h
, picref
);
921 draw_bar(test
, wobnair
[i
], x
, r_h
, r_w
, w_h
, picref
);
925 draw_bar(test
, i_pixel
, x
, r_h
+ w_h
, p_w
, p_h
, picref
);
927 draw_bar(test
, white
, x
, r_h
+ w_h
, p_w
, p_h
, picref
);
929 draw_bar(test
, q_pixel
, x
, r_h
+ w_h
, p_w
, p_h
, picref
);
931 tmp
= FFALIGN(5 * r_w
- x
, 1 << pixdesc
->log2_chroma_w
);
932 draw_bar(test
, black
, x
, r_h
+ w_h
, tmp
, p_h
, picref
);
934 tmp
= FFALIGN(r_w
/ 3, 1 << pixdesc
->log2_chroma_w
);
935 draw_bar(test
, neg4ire
, x
, r_h
+ w_h
, tmp
, p_h
, picref
);
937 draw_bar(test
, black
, x
, r_h
+ w_h
, tmp
, p_h
, picref
);
939 draw_bar(test
, pos4ire
, x
, r_h
+ w_h
, tmp
, p_h
, picref
);
941 draw_bar(test
, black
, x
, r_h
+ w_h
, test
->w
- x
, p_h
, picref
);
944 static av_cold
int smptebars_init(AVFilterContext
*ctx
)
946 TestSourceContext
*test
= ctx
->priv
;
948 test
->fill_picture_fn
= smptebars_fill_picture
;
953 AVFilter ff_vsrc_smptebars
= {
955 .description
= NULL_IF_CONFIG_SMALL("Generate SMPTE color bars."),
956 .priv_size
= sizeof(TestSourceContext
),
957 .priv_class
= &smptebars_class
,
958 .init
= smptebars_init
,
960 .query_formats
= smptebars_query_formats
,
962 .outputs
= smptebars_outputs
,
965 #endif /* CONFIG_SMPTEBARS_FILTER */
967 #if CONFIG_SMPTEHDBARS_FILTER
969 #define smptehdbars_options options
970 AVFILTER_DEFINE_CLASS(smptehdbars
);
972 static void smptehdbars_fill_picture(AVFilterContext
*ctx
, AVFrame
*picref
)
974 TestSourceContext
*test
= ctx
->priv
;
975 int d_w
, r_w
, r_h
, l_w
, i
, tmp
, x
= 0, y
= 0;
976 const AVPixFmtDescriptor
*pixdesc
= av_pix_fmt_desc_get(picref
->format
);
978 av_frame_set_colorspace(picref
, AVCOL_SPC_BT709
);
980 d_w
= FFALIGN(test
->w
/ 8, 1 << pixdesc
->log2_chroma_w
);
981 r_h
= FFALIGN(test
->h
* 7 / 12, 1 << pixdesc
->log2_chroma_h
);
982 draw_bar(test
, gray40
, x
, 0, d_w
, r_h
, picref
);
985 r_w
= FFALIGN((((test
->w
+ 3) / 4) * 3) / 7, 1 << pixdesc
->log2_chroma_w
);
986 for (i
= 0; i
< 7; i
++) {
987 draw_bar(test
, rainbow
[i
], x
, 0, r_w
, r_h
, picref
);
990 draw_bar(test
, gray40
, x
, 0, test
->w
- x
, r_h
, picref
);
992 r_h
= FFALIGN(test
->h
/ 12, 1 << pixdesc
->log2_chroma_h
);
993 draw_bar(test
, cyan
, 0, y
, d_w
, r_h
, picref
);
995 draw_bar(test
, i_pixel
, x
, y
, r_w
, r_h
, picref
);
998 draw_bar(test
, rainbow
[0], x
, y
, tmp
, r_h
, picref
);
1001 draw_bar(test
, blue
, x
, y
, test
->w
- x
, r_h
, picref
);
1003 draw_bar(test
, yellow
, 0, y
, d_w
, r_h
, picref
);
1005 draw_bar(test
, q_pixel
, x
, y
, r_w
, r_h
, picref
);
1008 for (i
= 0; i
< tmp
; i
+= 1 << pixdesc
->log2_chroma_w
) {
1009 uint8_t yramp
[4] = {0};
1011 yramp
[0] = i
* 255 / tmp
;
1016 draw_bar(test
, yramp
, x
, y
, 1 << pixdesc
->log2_chroma_w
, r_h
, picref
);
1017 x
+= 1 << pixdesc
->log2_chroma_w
;
1019 draw_bar(test
, red
, x
, y
, test
->w
- x
, r_h
, picref
);
1021 draw_bar(test
, gray15
, 0, y
, d_w
, test
->h
- y
, picref
);
1023 tmp
= FFALIGN(r_w
* 3 / 2, 1 << pixdesc
->log2_chroma_w
);
1024 draw_bar(test
, black0
, x
, y
, tmp
, test
->h
- y
, picref
);
1026 tmp
= FFALIGN(r_w
* 2, 1 << pixdesc
->log2_chroma_w
);
1027 draw_bar(test
, white
, x
, y
, tmp
, test
->h
- y
, picref
);
1029 tmp
= FFALIGN(r_w
* 5 / 6, 1 << pixdesc
->log2_chroma_w
);
1030 draw_bar(test
, black0
, x
, y
, tmp
, test
->h
- y
, picref
);
1032 tmp
= FFALIGN(r_w
/ 3, 1 << pixdesc
->log2_chroma_w
);
1033 draw_bar(test
, neg2
, x
, y
, tmp
, test
->h
- y
, picref
);
1035 draw_bar(test
, black0
, x
, y
, tmp
, test
->h
- y
, picref
);
1037 draw_bar(test
, black2
, x
, y
, tmp
, test
->h
- y
, picref
);
1039 draw_bar(test
, black0
, x
, y
, tmp
, test
->h
- y
, picref
);
1041 draw_bar(test
, black4
, x
, y
, tmp
, test
->h
- y
, picref
);
1044 draw_bar(test
, black0
, x
, y
, r_w
, test
->h
- y
, picref
);
1046 draw_bar(test
, gray15
, x
, y
, test
->w
- x
, test
->h
- y
, picref
);
1049 static av_cold
int smptehdbars_init(AVFilterContext
*ctx
)
1051 TestSourceContext
*test
= ctx
->priv
;
1053 test
->fill_picture_fn
= smptehdbars_fill_picture
;
1054 test
->draw_once
= 1;
1058 AVFilter ff_vsrc_smptehdbars
= {
1059 .name
= "smptehdbars",
1060 .description
= NULL_IF_CONFIG_SMALL("Generate SMPTE HD color bars."),
1061 .priv_size
= sizeof(TestSourceContext
),
1062 .priv_class
= &smptehdbars_class
,
1063 .init
= smptehdbars_init
,
1065 .query_formats
= smptebars_query_formats
,
1067 .outputs
= smptebars_outputs
,
1070 #endif /* CONFIG_SMPTEHDBARS_FILTER */
1071 #endif /* CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER */