2 * Copyright (C) 2003-2011 Michael Niedermayer <michaelni@gmx.at>
4 * This file is part of FFmpeg.
6 * FFmpeg 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 * 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 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 FFmpeg; 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_YA8 || \
41 (x) == AV_PIX_FMT_GRAY16BE || \
42 (x) == AV_PIX_FMT_GRAY16LE || \
43 (x) == AV_PIX_FMT_YA16BE || \
44 (x) == AV_PIX_FMT_YA16LE)
45 #define hasChroma(x) \
47 (x) == AV_PIX_FMT_MONOBLACK || \
48 (x) == AV_PIX_FMT_MONOWHITE))
50 ((x) == AV_PIX_FMT_BGR32 || \
51 (x) == AV_PIX_FMT_BGR32_1 || \
52 (x) == AV_PIX_FMT_RGB32 || \
53 (x) == AV_PIX_FMT_RGB32_1 || \
54 (x) == AV_PIX_FMT_YUVA420P)
56 static uint64_t getSSD(const uint8_t *src1
, const uint8_t *src2
, int stride1
,
57 int stride2
, int w
, int h
)
62 for (y
= 0; y
< h
; y
++) {
63 for (x
= 0; x
< w
; x
++) {
64 int d
= src1
[x
+ y
* stride1
] - src2
[x
+ y
* stride2
];
79 // test by ref -> src -> dst -> out & compare out against ref
81 static int doTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
,
82 enum AVPixelFormat srcFormat
, enum AVPixelFormat dstFormat
,
83 int srcW
, int srcH
, int dstW
, int dstH
, int flags
,
86 const AVPixFmtDescriptor
*desc_yuva420p
= av_pix_fmt_desc_get(AV_PIX_FMT_YUVA420P
);
87 const AVPixFmtDescriptor
*desc_src
= av_pix_fmt_desc_get(srcFormat
);
88 const AVPixFmtDescriptor
*desc_dst
= av_pix_fmt_desc_get(dstFormat
);
89 static enum AVPixelFormat cur_srcFormat
;
90 static int cur_srcW
, cur_srcH
;
91 static uint8_t *src
[4];
92 static int srcStride
[4];
93 uint8_t *dst
[4] = { 0 };
94 uint8_t *out
[4] = { 0 };
95 int dstStride
[4] = {0};
97 uint64_t ssdY
, ssdU
= 0, ssdV
= 0, ssdA
= 0;
98 struct SwsContext
*dstContext
= NULL
, *outContext
= NULL
;
102 if (cur_srcFormat
!= srcFormat
|| cur_srcW
!= srcW
|| cur_srcH
!= srcH
) {
103 struct SwsContext
*srcContext
= NULL
;
106 for (p
= 0; p
< 4; p
++)
109 av_image_fill_linesizes(srcStride
, srcFormat
, srcW
);
110 for (p
= 0; p
< 4; p
++) {
111 srcStride
[p
] = FFALIGN(srcStride
[p
], 16);
113 src
[p
] = av_mallocz(srcStride
[p
] * srcH
+ 16);
114 if (srcStride
[p
] && !src
[p
]) {
120 srcContext
= sws_getContext(w
, h
, AV_PIX_FMT_YUVA420P
, srcW
, srcH
,
121 srcFormat
, SWS_BILINEAR
, NULL
, NULL
, NULL
);
123 fprintf(stderr
, "Failed to get %s ---> %s\n",
129 sws_scale(srcContext
, (const uint8_t * const*)ref
, refStride
, 0, h
, src
, srcStride
);
130 sws_freeContext(srcContext
);
132 cur_srcFormat
= srcFormat
;
137 av_image_fill_linesizes(dstStride
, dstFormat
, dstW
);
138 for (i
= 0; i
< 4; i
++) {
139 /* Image buffers passed into libswscale can be allocated any way you
140 * prefer, as long as they're aligned enough for the architecture, and
141 * they're freed appropriately (such as using av_free for buffers
142 * allocated with av_malloc). */
143 /* An extra 16 bytes is being allocated because some scalers may write
145 dstStride
[i
] = FFALIGN(dstStride
[i
], 16);
147 dst
[i
] = av_mallocz(dstStride
[i
] * dstH
+ 16);
148 if (dstStride
[i
] && !dst
[i
]) {
156 dstContext
= sws_getContext(srcW
, srcH
, srcFormat
, dstW
, dstH
, dstFormat
,
157 flags
, NULL
, NULL
, NULL
);
159 fprintf(stderr
, "Failed to get %s ---> %s\n",
160 desc_src
->name
, desc_dst
->name
);
165 printf(" %s %dx%d -> %s %3dx%3d flags=%2d",
166 desc_src
->name
, srcW
, srcH
,
167 desc_dst
->name
, dstW
, dstH
,
171 sws_scale(dstContext
, (const uint8_t * const*)src
, srcStride
, 0, srcH
, dst
, dstStride
);
173 for (i
= 0; i
< 4 && dstStride
[i
]; i
++)
174 crc
= av_crc(av_crc_get_table(AV_CRC_32_IEEE
), crc
, dst
[i
],
175 dstStride
[i
] * dstH
);
177 if (r
&& crc
== r
->crc
) {
183 for (i
= 0; i
< 4; i
++) {
184 refStride
[i
] = FFALIGN(refStride
[i
], 16);
186 out
[i
] = av_mallocz(refStride
[i
] * h
);
187 if (refStride
[i
] && !out
[i
]) {
193 outContext
= sws_getContext(dstW
, dstH
, dstFormat
, w
, h
,
194 AV_PIX_FMT_YUVA420P
, SWS_BILINEAR
,
197 fprintf(stderr
, "Failed to get %s ---> %s\n",
199 desc_yuva420p
->name
);
203 sws_scale(outContext
, (const uint8_t * const*)dst
, dstStride
, 0, dstH
, out
, refStride
);
205 ssdY
= getSSD(ref
[0], out
[0], refStride
[0], refStride
[0], w
, h
);
206 if (hasChroma(srcFormat
) && hasChroma(dstFormat
)) {
207 //FIXME check that output is really gray
208 ssdU
= getSSD(ref
[1], out
[1], refStride
[1], refStride
[1],
209 (w
+ 1) >> 1, (h
+ 1) >> 1);
210 ssdV
= getSSD(ref
[2], out
[2], refStride
[2], refStride
[2],
211 (w
+ 1) >> 1, (h
+ 1) >> 1);
213 if (isALPHA(srcFormat
) && isALPHA(dstFormat
))
214 ssdA
= getSSD(ref
[3], out
[3], refStride
[3], refStride
[3], w
, h
);
221 sws_freeContext(outContext
);
223 for (i
= 0; i
< 4; i
++)
228 printf(" CRC=%08x SSD=%5"PRId64
",%5"PRId64
",%5"PRId64
",%5"PRId64
"\n",
229 crc
, ssdY
, ssdU
, ssdV
, ssdA
);
232 sws_freeContext(dstContext
);
234 for (i
= 0; i
< 4; i
++)
241 static void selfTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
,
242 enum AVPixelFormat srcFormat_in
,
243 enum AVPixelFormat dstFormat_in
)
245 const int flags
[] = { SWS_FAST_BILINEAR
, SWS_BILINEAR
, SWS_BICUBIC
,
246 SWS_X
, SWS_POINT
, SWS_AREA
, 0 };
249 const int dstW
[] = { srcW
- srcW
/ 3, srcW
, srcW
+ srcW
/ 3, 0 };
250 const int dstH
[] = { srcH
- srcH
/ 3, srcH
, srcH
+ srcH
/ 3, 0 };
251 enum AVPixelFormat srcFormat
, dstFormat
;
252 const AVPixFmtDescriptor
*desc_src
, *desc_dst
;
254 for (srcFormat
= srcFormat_in
!= AV_PIX_FMT_NONE
? srcFormat_in
: 0;
255 srcFormat
< AV_PIX_FMT_NB
; srcFormat
++) {
256 if (!sws_isSupportedInput(srcFormat
) ||
257 !sws_isSupportedOutput(srcFormat
))
260 desc_src
= av_pix_fmt_desc_get(srcFormat
);
262 for (dstFormat
= dstFormat_in
!= AV_PIX_FMT_NONE
? dstFormat_in
: 0;
263 dstFormat
< AV_PIX_FMT_NB
; dstFormat
++) {
267 if (!sws_isSupportedInput(dstFormat
) ||
268 !sws_isSupportedOutput(dstFormat
))
271 desc_dst
= av_pix_fmt_desc_get(dstFormat
);
273 printf("%s -> %s\n", desc_src
->name
, desc_dst
->name
);
276 for (k
= 0; flags
[k
] && !res
; k
++)
277 for (i
= 0; dstW
[i
] && !res
; i
++)
278 for (j
= 0; dstH
[j
] && !res
; j
++)
279 res
= doTest(ref
, refStride
, w
, h
,
280 srcFormat
, dstFormat
,
281 srcW
, srcH
, dstW
[i
], dstH
[j
], flags
[k
],
283 if (dstFormat_in
!= AV_PIX_FMT_NONE
)
286 if (srcFormat_in
!= AV_PIX_FMT_NONE
)
291 static int fileTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
, FILE *fp
,
292 enum AVPixelFormat srcFormat_in
,
293 enum AVPixelFormat dstFormat_in
)
297 while (fgets(buf
, sizeof(buf
), fp
)) {
299 enum AVPixelFormat srcFormat
;
302 enum AVPixelFormat dstFormat
;
309 " %12s %dx%d -> %12s %dx%d flags=%d CRC=%x"
310 " SSD=%"SCNd64
", %"SCNd64
", %"SCNd64
", %"SCNd64
"\n",
311 srcStr
, &srcW
, &srcH
, dstStr
, &dstW
, &dstH
,
312 &flags
, &r
.crc
, &r
.ssdY
, &r
.ssdU
, &r
.ssdV
, &r
.ssdA
);
314 srcStr
[0] = dstStr
[0] = 0;
315 ret
= sscanf(buf
, "%12s -> %12s\n", srcStr
, dstStr
);
318 srcFormat
= av_get_pix_fmt(srcStr
);
319 dstFormat
= av_get_pix_fmt(dstStr
);
321 if (srcFormat
== AV_PIX_FMT_NONE
|| dstFormat
== AV_PIX_FMT_NONE
||
322 srcW
> 8192U || srcH
> 8192U || dstW
> 8192U || dstH
> 8192U) {
323 fprintf(stderr
, "malformed input file\n");
326 if ((srcFormat_in
!= AV_PIX_FMT_NONE
&& srcFormat_in
!= srcFormat
) ||
327 (dstFormat_in
!= AV_PIX_FMT_NONE
&& dstFormat_in
!= dstFormat
))
334 doTest(ref
, refStride
, w
, h
,
335 srcFormat
, dstFormat
,
336 srcW
, srcH
, dstW
, dstH
, flags
,
346 int main(int argc
, char **argv
)
348 enum AVPixelFormat srcFormat
= AV_PIX_FMT_NONE
;
349 enum AVPixelFormat dstFormat
= AV_PIX_FMT_NONE
;
350 uint8_t *rgb_data
= av_malloc(W
* H
* 4);
351 const uint8_t * const rgb_src
[4] = { rgb_data
, NULL
, NULL
, NULL
};
352 int rgb_stride
[4] = { 4 * W
, 0, 0, 0 };
353 uint8_t *data
= av_malloc(4 * W
* H
);
354 uint8_t *src
[4] = { data
, data
+ W
* H
, data
+ W
* H
* 2, data
+ W
* H
* 3 };
355 int stride
[4] = { W
, W
, W
, W
};
357 struct SwsContext
*sws
;
363 if (!rgb_data
|| !data
)
366 for (i
= 1; i
< argc
; i
+= 2) {
367 if (argv
[i
][0] != '-' || i
+ 1 == argc
)
369 if (!strcmp(argv
[i
], "-ref")) {
370 fp
= fopen(argv
[i
+ 1], "r");
372 fprintf(stderr
, "could not open '%s'\n", argv
[i
+ 1]);
375 } else if (!strcmp(argv
[i
], "-src")) {
376 srcFormat
= av_get_pix_fmt(argv
[i
+ 1]);
377 if (srcFormat
== AV_PIX_FMT_NONE
) {
378 fprintf(stderr
, "invalid pixel format %s\n", argv
[i
+ 1]);
381 } else if (!strcmp(argv
[i
], "-dst")) {
382 dstFormat
= av_get_pix_fmt(argv
[i
+ 1]);
383 if (dstFormat
== AV_PIX_FMT_NONE
) {
384 fprintf(stderr
, "invalid pixel format %s\n", argv
[i
+ 1]);
389 fprintf(stderr
, "bad option or argument missing (%s)\n", argv
[i
]);
394 sws
= sws_getContext(W
/ 12, H
/ 12, AV_PIX_FMT_RGB32
, W
, H
,
395 AV_PIX_FMT_YUVA420P
, SWS_BILINEAR
, NULL
, NULL
, NULL
);
397 av_lfg_init(&rand
, 1);
399 for (y
= 0; y
< H
; y
++)
400 for (x
= 0; x
< W
* 4; x
++)
401 rgb_data
[ x
+ y
* 4 * W
] = av_lfg_get(&rand
);
402 sws_scale(sws
, rgb_src
, rgb_stride
, 0, H
, src
, stride
);
403 sws_freeContext(sws
);
407 res
= fileTest(src
, stride
, W
, H
, fp
, srcFormat
, dstFormat
);
410 selfTest(src
, stride
, W
, H
, srcFormat
, dstFormat
);