2 * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * MP test source, ported from MPlayer libmpcodecs/vf_test.c
26 #include "libavutil/avstring.h"
27 #include "libavutil/opt.h"
28 #include "libavutil/parseutils.h"
29 #include "libavutil/pixdesc.h"
53 typedef struct MPTestContext
{
55 AVRational frame_rate
;
56 int64_t pts
, max_pts
, duration
;
61 #define OFFSET(x) offsetof(MPTestContext, x)
62 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
63 static const AVOption mptestsrc_options
[]= {
64 { "rate", "set video rate", OFFSET(frame_rate
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, 0, FLAGS
},
65 { "r", "set video rate", OFFSET(frame_rate
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, 0, FLAGS
},
66 { "duration", "set video duration", OFFSET(duration
), AV_OPT_TYPE_DURATION
, {.i64
= -1}, -1, INT64_MAX
, FLAGS
},
67 { "d", "set video duration", OFFSET(duration
), AV_OPT_TYPE_DURATION
, {.i64
= -1}, -1, INT64_MAX
, FLAGS
},
69 { "test", "set test to perform", OFFSET(test
), AV_OPT_TYPE_INT
, {.i64
=TEST_ALL
}, 0, INT_MAX
, FLAGS
, "test" },
70 { "t", "set test to perform", OFFSET(test
), AV_OPT_TYPE_INT
, {.i64
=TEST_ALL
}, 0, INT_MAX
, FLAGS
, "test" },
71 { "dc_luma", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_DC_LUMA
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
72 { "dc_chroma", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_DC_CHROMA
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
73 { "freq_luma", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_FREQ_LUMA
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
74 { "freq_chroma", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_FREQ_CHROMA
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
75 { "amp_luma", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_AMP_LUMA
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
76 { "amp_chroma", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_AMP_CHROMA
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
77 { "cbp", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_CBP
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
78 { "mv", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_MV
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
79 { "ring1", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_RING1
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
80 { "ring2", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_RING2
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
81 { "all", "", 0, AV_OPT_TYPE_CONST
, {.i64
=TEST_ALL
}, INT_MIN
, INT_MAX
, FLAGS
, "test" },
85 AVFILTER_DEFINE_CLASS(mptestsrc
);
89 static void init_idct(void)
93 for (i
= 0; i
< 8; i
++) {
94 double s
= i
== 0 ? sqrt(0.125) : 0.5;
96 for (j
= 0; j
< 8; j
++)
97 c
[i
*8+j
] = s
*cos((M_PI
/8.0)*i
*(j
+0.5));
101 static void idct(uint8_t *dst
, int dst_linesize
, int src
[64])
106 for (i
= 0; i
< 8; i
++) {
107 for (j
= 0; j
< 8; j
++) {
110 for (k
= 0; k
< 8; k
++)
111 sum
+= c
[k
*8+j
] * src
[8*i
+k
];
117 for (j
= 0; j
< 8; j
++) {
118 for (i
= 0; i
< 8; i
++) {
121 for (k
= 0; k
< 8; k
++)
122 sum
+= c
[k
*8+i
]*tmp
[8*k
+j
];
124 dst
[dst_linesize
*i
+ j
] = av_clip((int)floor(sum
+0.5), 0, 255);
129 static void draw_dc(uint8_t *dst
, int dst_linesize
, int color
, int w
, int h
)
133 for (y
= 0; y
< h
; y
++)
134 for (x
= 0; x
< w
; x
++)
135 dst
[x
+ y
*dst_linesize
] = color
;
138 static void draw_basis(uint8_t *dst
, int dst_linesize
, int amp
, int freq
, int dc
)
142 memset(src
, 0, 64*sizeof(int));
146 idct(dst
, dst_linesize
, src
);
149 static void draw_cbp(uint8_t *dst
[3], int dst_linesize
[3], int cbp
, int amp
, int dc
)
151 if (cbp
&1) draw_basis(dst
[0] , dst_linesize
[0], amp
, 1, dc
);
152 if (cbp
&2) draw_basis(dst
[0]+8 , dst_linesize
[0], amp
, 1, dc
);
153 if (cbp
&4) draw_basis(dst
[0]+ 8*dst_linesize
[0], dst_linesize
[0], amp
, 1, dc
);
154 if (cbp
&8) draw_basis(dst
[0]+8+8*dst_linesize
[0], dst_linesize
[0], amp
, 1, dc
);
155 if (cbp
&16) draw_basis(dst
[1] , dst_linesize
[1], amp
, 1, dc
);
156 if (cbp
&32) draw_basis(dst
[2] , dst_linesize
[2], amp
, 1, dc
);
159 static void dc_test(uint8_t *dst
, int dst_linesize
, int w
, int h
, int off
)
161 const int step
= FFMAX(256/(w
*h
/256), 1);
162 int x
, y
, color
= off
;
164 for (y
= 0; y
< h
; y
+= 16) {
165 for (x
= 0; x
< w
; x
+= 16) {
166 draw_dc(dst
+ x
+ y
*dst_linesize
, dst_linesize
, color
, 8, 8);
172 static void freq_test(uint8_t *dst
, int dst_linesize
, int off
)
176 for (y
= 0; y
< 8*16; y
+= 16) {
177 for (x
= 0; x
< 8*16; x
+= 16) {
178 draw_basis(dst
+ x
+ y
*dst_linesize
, dst_linesize
, 4*(96+off
), freq
, 128*8);
184 static void amp_test(uint8_t *dst
, int dst_linesize
, int off
)
188 for (y
= 0; y
< 16*16; y
+= 16) {
189 for (x
= 0; x
< 16*16; x
+= 16) {
190 draw_basis(dst
+ x
+ y
*dst_linesize
, dst_linesize
, 4*amp
, 1, 128*8);
196 static void cbp_test(uint8_t *dst
[3], int dst_linesize
[3], int off
)
200 for (y
= 0; y
< 16*8; y
+= 16) {
201 for (x
= 0; x
< 16*8; x
+= 16) {
203 dst1
[0] = dst
[0] + x
*2 + y
*2*dst_linesize
[0];
204 dst1
[1] = dst
[1] + x
+ y
* dst_linesize
[1];
205 dst1
[2] = dst
[2] + x
+ y
* dst_linesize
[2];
207 draw_cbp(dst1
, dst_linesize
, cbp
, (64+off
)*4, 128*8);
213 static void mv_test(uint8_t *dst
, int dst_linesize
, int off
)
217 for (y
= 0; y
< 16*16; y
++) {
220 for (x
= 0; x
< 16*16; x
++)
221 dst
[x
+ y
*dst_linesize
] = x
+ off
*8/(y
/32+1);
225 static void ring1_test(uint8_t *dst
, int dst_linesize
, int off
)
229 for (y
= off
; y
< 16*16; y
+= 16) {
230 for (x
= off
; x
< 16*16; x
+= 16) {
231 draw_dc(dst
+ x
+ y
*dst_linesize
, dst_linesize
, ((x
+y
)&16) ? color
: -color
, 16, 16);
237 static void ring2_test(uint8_t *dst
, int dst_linesize
, int off
)
241 for (y
= 0; y
< 16*16; y
++) {
242 for (x
= 0; x
< 16*16; x
++) {
243 double d
= sqrt((x
-8*16)*(x
-8*16) + (y
-8*16)*(y
-8*16));
244 double r
= d
/20 - (int)(d
/20);
246 dst
[x
+ y
*dst_linesize
] = 255;
247 dst
[x
+ y
*dst_linesize
+256] = 0;
249 dst
[x
+ y
*dst_linesize
] = x
;
250 dst
[x
+ y
*dst_linesize
+256] = x
;
256 static av_cold
int init(AVFilterContext
*ctx
)
258 MPTestContext
*test
= ctx
->priv
;
260 test
->max_pts
= test
->duration
>= 0 ?
261 av_rescale_q(test
->duration
, AV_TIME_BASE_Q
, av_inv_q(test
->frame_rate
)) : -1;
264 av_log(ctx
, AV_LOG_VERBOSE
, "rate:%d/%d duration:%f\n",
265 test
->frame_rate
.num
, test
->frame_rate
.den
,
266 test
->duration
< 0 ? -1 : test
->max_pts
* av_q2d(av_inv_q(test
->frame_rate
)));
272 static int config_props(AVFilterLink
*outlink
)
274 AVFilterContext
*ctx
= outlink
->src
;
275 MPTestContext
*test
= ctx
->priv
;
276 const AVPixFmtDescriptor
*pix_desc
= av_pix_fmt_desc_get(outlink
->format
);
278 test
->hsub
= pix_desc
->log2_chroma_w
;
279 test
->vsub
= pix_desc
->log2_chroma_h
;
283 outlink
->time_base
= av_inv_q(test
->frame_rate
);
288 static int query_formats(AVFilterContext
*ctx
)
290 static const enum AVPixelFormat pix_fmts
[] = {
291 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_NONE
294 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
298 static int request_frame(AVFilterLink
*outlink
)
300 MPTestContext
*test
= outlink
->src
->priv
;
302 int w
= WIDTH
, h
= HEIGHT
,
303 cw
= FF_CEIL_RSHIFT(w
, test
->hsub
), ch
= FF_CEIL_RSHIFT(h
, test
->vsub
);
304 unsigned int frame
= outlink
->frame_count
;
305 enum test_type tt
= test
->test
;
308 if (test
->max_pts
>= 0 && test
->pts
> test
->max_pts
)
310 picref
= ff_get_video_buffer(outlink
, w
, h
);
312 return AVERROR(ENOMEM
);
313 picref
->pts
= test
->pts
++;
316 for (i
= 0; i
< h
; i
++)
317 memset(picref
->data
[0] + i
*picref
->linesize
[0], 0, w
);
318 for (i
= 0; i
< ch
; i
++) {
319 memset(picref
->data
[1] + i
*picref
->linesize
[1], 128, cw
);
320 memset(picref
->data
[2] + i
*picref
->linesize
[2], 128, cw
);
323 if (tt
== TEST_ALL
&& frame
%30) /* draw a black frame at the beginning of each test */
324 tt
= (frame
/30)%(TEST_NB
-1);
327 case TEST_DC_LUMA
: dc_test(picref
->data
[0], picref
->linesize
[0], 256, 256, frame
%30); break;
328 case TEST_DC_CHROMA
: dc_test(picref
->data
[1], picref
->linesize
[1], 256, 256, frame
%30); break;
329 case TEST_FREQ_LUMA
: freq_test(picref
->data
[0], picref
->linesize
[0], frame
%30); break;
330 case TEST_FREQ_CHROMA
: freq_test(picref
->data
[1], picref
->linesize
[1], frame
%30); break;
331 case TEST_AMP_LUMA
: amp_test(picref
->data
[0], picref
->linesize
[0], frame
%30); break;
332 case TEST_AMP_CHROMA
: amp_test(picref
->data
[1], picref
->linesize
[1], frame
%30); break;
333 case TEST_CBP
: cbp_test(picref
->data
, picref
->linesize
, frame
%30); break;
334 case TEST_MV
: mv_test(picref
->data
[0], picref
->linesize
[0], frame
%30); break;
335 case TEST_RING1
: ring1_test(picref
->data
[0], picref
->linesize
[0], frame
%30); break;
336 case TEST_RING2
: ring2_test(picref
->data
[0], picref
->linesize
[0], frame
%30); break;
339 return ff_filter_frame(outlink
, picref
);
342 static const AVFilterPad mptestsrc_outputs
[] = {
345 .type
= AVMEDIA_TYPE_VIDEO
,
346 .request_frame
= request_frame
,
347 .config_props
= config_props
,
352 AVFilter ff_vsrc_mptestsrc
= {
354 .description
= NULL_IF_CONFIG_SMALL("Generate various test pattern."),
355 .priv_size
= sizeof(MPTestContext
),
356 .priv_class
= &mptestsrc_class
,
358 .query_formats
= query_formats
,
360 .outputs
= mptestsrc_outputs
,