2 * Copyright (C) 2003 Michael Niedermayer <michaelni@gmx.at>
4 * This file is part of Libav.
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libav 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #undef HAVE_AV_CONFIG_H
28 #include "libavutil/imgutils.h"
29 #include "libavutil/mem.h"
30 #include "libavutil/avutil.h"
31 #include "libavutil/crc.h"
32 #include "libavutil/pixdesc.h"
33 #include "libavutil/lfg.h"
36 /* HACK Duplicated from swscale_internal.h.
37 * Should be removed when a cleaner pixel format system exists. */
39 ((x) == AV_PIX_FMT_GRAY8 || \
40 (x) == AV_PIX_FMT_Y400A || \
41 (x) == AV_PIX_FMT_GRAY16BE || \
42 (x) == AV_PIX_FMT_GRAY16LE)
43 #define hasChroma(x) \
45 (x) == AV_PIX_FMT_MONOBLACK || \
46 (x) == AV_PIX_FMT_MONOWHITE))
48 ((x) == AV_PIX_FMT_BGR32 || \
49 (x) == AV_PIX_FMT_BGR32_1 || \
50 (x) == AV_PIX_FMT_RGB32 || \
51 (x) == AV_PIX_FMT_RGB32_1 || \
52 (x) == AV_PIX_FMT_YUVA420P)
54 static uint64_t getSSD(uint8_t *src1
, uint8_t *src2
, int stride1
,
55 int stride2
, int w
, int h
)
60 for (y
= 0; y
< h
; y
++) {
61 for (x
= 0; x
< w
; x
++) {
62 int d
= src1
[x
+ y
* stride1
] - src2
[x
+ y
* stride2
];
77 // test by ref -> src -> dst -> out & compare out against ref
79 static int doTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
,
80 enum AVPixelFormat srcFormat
, enum AVPixelFormat dstFormat
,
81 int srcW
, int srcH
, int dstW
, int dstH
, int flags
,
84 const AVPixFmtDescriptor
*desc_yuva420p
= av_pix_fmt_desc_get(AV_PIX_FMT_YUVA420P
);
85 const AVPixFmtDescriptor
*desc_src
= av_pix_fmt_desc_get(srcFormat
);
86 const AVPixFmtDescriptor
*desc_dst
= av_pix_fmt_desc_get(dstFormat
);
87 static enum AVPixelFormat cur_srcFormat
;
88 static int cur_srcW
, cur_srcH
;
89 static uint8_t *src
[4];
90 static int srcStride
[4];
91 uint8_t *dst
[4] = { 0 };
92 uint8_t *out
[4] = { 0 };
95 uint64_t ssdY
, ssdU
= 0, ssdV
= 0, ssdA
= 0;
96 struct SwsContext
*dstContext
= NULL
, *outContext
= NULL
;
100 if (cur_srcFormat
!= srcFormat
|| cur_srcW
!= srcW
|| cur_srcH
!= srcH
) {
101 struct SwsContext
*srcContext
= NULL
;
104 for (p
= 0; p
< 4; p
++)
107 av_image_fill_linesizes(srcStride
, srcFormat
, srcW
);
108 for (p
= 0; p
< 4; p
++) {
110 src
[p
] = av_mallocz(srcStride
[p
] * srcH
+ 16);
111 if (srcStride
[p
] && !src
[p
]) {
117 srcContext
= sws_getContext(w
, h
, AV_PIX_FMT_YUVA420P
, srcW
, srcH
,
118 srcFormat
, SWS_BILINEAR
, NULL
, NULL
, NULL
);
120 fprintf(stderr
, "Failed to get %s ---> %s\n",
126 sws_scale(srcContext
, ref
, refStride
, 0, h
, src
, srcStride
);
127 sws_freeContext(srcContext
);
129 cur_srcFormat
= srcFormat
;
134 av_image_fill_linesizes(dstStride
, dstFormat
, dstW
);
135 for (i
= 0; i
< 4; i
++) {
136 /* Image buffers passed into libswscale can be allocated any way you
137 * prefer, as long as they're aligned enough for the architecture, and
138 * they're freed appropriately (such as using av_free for buffers
139 * allocated with av_malloc). */
140 /* An extra 16 bytes is being allocated because some scalers may write
143 dst
[i
] = av_mallocz(dstStride
[i
] * dstH
+ 16);
144 if (dstStride
[i
] && !dst
[i
]) {
152 dstContext
= sws_getContext(srcW
, srcH
, srcFormat
, dstW
, dstH
, dstFormat
,
153 flags
, NULL
, NULL
, NULL
);
155 fprintf(stderr
, "Failed to get %s ---> %s\n",
156 desc_src
->name
, desc_dst
->name
);
161 printf(" %s %dx%d -> %s %3dx%3d flags=%2d",
162 desc_src
->name
, srcW
, srcH
,
163 desc_dst
->name
, dstW
, dstH
,
167 sws_scale(dstContext
, src
, srcStride
, 0, srcH
, dst
, dstStride
);
169 for (i
= 0; i
< 4 && dstStride
[i
]; i
++)
170 crc
= av_crc(av_crc_get_table(AV_CRC_32_IEEE
), crc
, dst
[i
],
171 dstStride
[i
] * dstH
);
173 if (r
&& crc
== r
->crc
) {
179 for (i
= 0; i
< 4; i
++) {
181 out
[i
] = av_mallocz(refStride
[i
] * h
);
182 if (refStride
[i
] && !out
[i
]) {
188 outContext
= sws_getContext(dstW
, dstH
, dstFormat
, w
, h
,
189 AV_PIX_FMT_YUVA420P
, SWS_BILINEAR
,
192 fprintf(stderr
, "Failed to get %s ---> %s\n",
194 desc_yuva420p
->name
);
198 sws_scale(outContext
, dst
, dstStride
, 0, dstH
, out
, refStride
);
200 ssdY
= getSSD(ref
[0], out
[0], refStride
[0], refStride
[0], w
, h
);
201 if (hasChroma(srcFormat
) && hasChroma(dstFormat
)) {
202 //FIXME check that output is really gray
203 ssdU
= getSSD(ref
[1], out
[1], refStride
[1], refStride
[1],
204 (w
+ 1) >> 1, (h
+ 1) >> 1);
205 ssdV
= getSSD(ref
[2], out
[2], refStride
[2], refStride
[2],
206 (w
+ 1) >> 1, (h
+ 1) >> 1);
208 if (isALPHA(srcFormat
) && isALPHA(dstFormat
))
209 ssdA
= getSSD(ref
[3], out
[3], refStride
[3], refStride
[3], w
, h
);
216 sws_freeContext(outContext
);
218 for (i
= 0; i
< 4; i
++)
223 printf(" CRC=%08x SSD=%5"PRId64
",%5"PRId64
",%5"PRId64
",%5"PRId64
"\n",
224 crc
, ssdY
, ssdU
, ssdV
, ssdA
);
227 sws_freeContext(dstContext
);
229 for (i
= 0; i
< 4; i
++)
236 static void selfTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
,
237 enum AVPixelFormat srcFormat_in
,
238 enum AVPixelFormat dstFormat_in
)
240 const int flags
[] = { SWS_FAST_BILINEAR
, SWS_BILINEAR
, SWS_BICUBIC
,
241 SWS_X
, SWS_POINT
, SWS_AREA
, 0 };
244 const int dstW
[] = { srcW
- srcW
/ 3, srcW
, srcW
+ srcW
/ 3, 0 };
245 const int dstH
[] = { srcH
- srcH
/ 3, srcH
, srcH
+ srcH
/ 3, 0 };
246 enum AVPixelFormat srcFormat
, dstFormat
;
247 const AVPixFmtDescriptor
*desc_src
, *desc_dst
;
249 for (srcFormat
= srcFormat_in
!= AV_PIX_FMT_NONE
? srcFormat_in
: 0;
250 srcFormat
< AV_PIX_FMT_NB
; srcFormat
++) {
251 if (!sws_isSupportedInput(srcFormat
) ||
252 !sws_isSupportedOutput(srcFormat
))
255 desc_src
= av_pix_fmt_desc_get(srcFormat
);
257 for (dstFormat
= dstFormat_in
!= AV_PIX_FMT_NONE
? dstFormat_in
: 0;
258 dstFormat
< AV_PIX_FMT_NB
; dstFormat
++) {
262 if (!sws_isSupportedInput(dstFormat
) ||
263 !sws_isSupportedOutput(dstFormat
))
266 desc_dst
= av_pix_fmt_desc_get(dstFormat
);
268 printf("%s -> %s\n", desc_src
->name
, desc_dst
->name
);
271 for (k
= 0; flags
[k
] && !res
; k
++)
272 for (i
= 0; dstW
[i
] && !res
; i
++)
273 for (j
= 0; dstH
[j
] && !res
; j
++)
274 res
= doTest(ref
, refStride
, w
, h
,
275 srcFormat
, dstFormat
,
276 srcW
, srcH
, dstW
[i
], dstH
[j
], flags
[k
],
278 if (dstFormat_in
!= AV_PIX_FMT_NONE
)
281 if (srcFormat_in
!= AV_PIX_FMT_NONE
)
286 static int fileTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
, FILE *fp
,
287 enum AVPixelFormat srcFormat_in
,
288 enum AVPixelFormat dstFormat_in
)
292 while (fgets(buf
, sizeof(buf
), fp
)) {
294 enum AVPixelFormat srcFormat
;
297 enum AVPixelFormat dstFormat
;
304 " %12s %dx%d -> %12s %dx%d flags=%d CRC=%x"
305 " SSD=%"PRId64
", %"PRId64
", %"PRId64
", %"PRId64
"\n",
306 srcStr
, &srcW
, &srcH
, dstStr
, &dstW
, &dstH
,
307 &flags
, &r
.crc
, &r
.ssdY
, &r
.ssdU
, &r
.ssdV
, &r
.ssdA
);
309 srcStr
[0] = dstStr
[0] = 0;
310 ret
= sscanf(buf
, "%12s -> %12s\n", srcStr
, dstStr
);
313 srcFormat
= av_get_pix_fmt(srcStr
);
314 dstFormat
= av_get_pix_fmt(dstStr
);
316 if (srcFormat
== AV_PIX_FMT_NONE
|| dstFormat
== AV_PIX_FMT_NONE
) {
317 fprintf(stderr
, "malformed input file\n");
320 if ((srcFormat_in
!= AV_PIX_FMT_NONE
&& srcFormat_in
!= srcFormat
) ||
321 (dstFormat_in
!= AV_PIX_FMT_NONE
&& dstFormat_in
!= dstFormat
))
328 doTest(ref
, refStride
, w
, h
,
329 srcFormat
, dstFormat
,
330 srcW
, srcH
, dstW
, dstH
, flags
,
340 int main(int argc
, char **argv
)
342 enum AVPixelFormat srcFormat
= AV_PIX_FMT_NONE
;
343 enum AVPixelFormat dstFormat
= AV_PIX_FMT_NONE
;
344 uint8_t *rgb_data
= av_malloc(W
* H
* 4);
345 uint8_t *rgb_src
[4] = { rgb_data
, NULL
, NULL
, NULL
};
346 int rgb_stride
[4] = { 4 * W
, 0, 0, 0 };
347 uint8_t *data
= av_malloc(4 * W
* H
);
348 uint8_t *src
[4] = { data
, data
+ W
* H
, data
+ W
* H
* 2, data
+ W
* H
* 3 };
349 int stride
[4] = { W
, W
, W
, W
};
351 struct SwsContext
*sws
;
356 if (!rgb_data
|| !data
)
359 sws
= sws_getContext(W
/ 12, H
/ 12, AV_PIX_FMT_RGB32
, W
, H
,
360 AV_PIX_FMT_YUVA420P
, SWS_BILINEAR
, NULL
, NULL
, NULL
);
362 av_lfg_init(&rand
, 1);
364 for (y
= 0; y
< H
; y
++)
365 for (x
= 0; x
< W
* 4; x
++)
366 rgb_data
[ x
+ y
* 4 * W
] = av_lfg_get(&rand
);
367 sws_scale(sws
, rgb_src
, rgb_stride
, 0, H
, src
, stride
);
368 sws_freeContext(sws
);
371 for (i
= 1; i
< argc
; i
+= 2) {
372 if (argv
[i
][0] != '-' || i
+ 1 == argc
)
374 if (!strcmp(argv
[i
], "-ref")) {
375 FILE *fp
= fopen(argv
[i
+ 1], "r");
377 fprintf(stderr
, "could not open '%s'\n", argv
[i
+ 1]);
380 res
= fileTest(src
, stride
, W
, H
, fp
, srcFormat
, dstFormat
);
383 } else if (!strcmp(argv
[i
], "-src")) {
384 srcFormat
= av_get_pix_fmt(argv
[i
+ 1]);
385 if (srcFormat
== AV_PIX_FMT_NONE
) {
386 fprintf(stderr
, "invalid pixel format %s\n", argv
[i
+ 1]);
389 } else if (!strcmp(argv
[i
], "-dst")) {
390 dstFormat
= av_get_pix_fmt(argv
[i
+ 1]);
391 if (dstFormat
== AV_PIX_FMT_NONE
) {
392 fprintf(stderr
, "invalid pixel format %s\n", argv
[i
+ 1]);
397 fprintf(stderr
, "bad option or argument missing (%s)\n", argv
[i
]);
402 selfTest(src
, stride
, W
, H
, srcFormat
, dstFormat
);